diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex index e7221fb980b..f798bd2dd7c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex @@ -88,14 +88,14 @@ CODE_LINK=\[{QUALIFIED_NAME}\] /* Example: @return[x] The return value of function x ^^^ */ - {CODE_LINK} { yybegin(CONTENTS); + {CODE_LINK} { yybegin(TAG_TEXT_BEGINNING); return KDocTokens.MARKDOWN_LINK; } /* Example: @param aaa The value of aaa ^^^ */ {QUALIFIED_NAME} { - yybegin(CONTENTS); + yybegin(TAG_TEXT_BEGINNING); return KDocTokens.MARKDOWN_LINK; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java index 0772ff9bafa..1365b992e75 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java @@ -1,4 +1,4 @@ -/* The following code was generated by JFlex 1.4.3 on 2/6/15 12:23 PM */ +/* The following code was generated by JFlex 1.4.3 on 3/5/15 7:51 PM */ package org.jetbrains.kotlin.kdoc.lexer; @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag; /** * This class is a scanner generated by * JFlex 1.4.3 - * on 2/6/15 12:23 PM from the specification file + * on 3/5/15 7:51 PM from the specification file * /Users/yole/jetbrains/kotlin/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex */ class _KDocLexer implements FlexLexer { @@ -117,11 +117,11 @@ class _KDocLexer implements FlexLexer { private static final String ZZ_ACTION_PACKED_0 = "\6\0\3\1\1\2\1\3\1\2\1\4\3\2\1\5"+ - "\1\6\1\7\2\5\1\0\1\10\2\0\1\11\1\12"+ - "\1\0\1\13\1\0\1\14\1\15"; + "\1\6\1\7\3\5\1\0\1\10\2\0\1\11\1\12"+ + "\2\0\1\13\1\0\1\14\1\15\1\16"; private static int [] zzUnpackAction() { - int [] result = new int[32]; + int [] result = new int[35]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -148,11 +148,12 @@ class _KDocLexer implements FlexLexer { private static final String ZZ_ROWMAP_PACKED_0 = "\0\0\0\15\0\32\0\47\0\64\0\101\0\116\0\133"+ "\0\150\0\116\0\165\0\202\0\217\0\234\0\150\0\251"+ - "\0\116\0\266\0\303\0\320\0\150\0\335\0\116\0\150"+ - "\0\352\0\116\0\367\0\u0104\0\116\0\u0111\0\116\0\116"; + "\0\116\0\266\0\303\0\320\0\150\0\335\0\352\0\116"+ + "\0\150\0\367\0\116\0\u0104\0\u0111\0\u011e\0\116\0\u012b"+ + "\0\116\0\116\0\116"; private static int [] zzUnpackRowMap() { - int [] result = new int[32]; + int [] result = new int[35]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -179,18 +180,18 @@ class _KDocLexer implements FlexLexer { "\3\12\1\14\2\12\1\15\1\12\1\13\1\16\2\12"+ "\1\13\3\12\1\14\2\12\1\17\1\20\1\13\1\16"+ "\1\12\1\21\1\22\1\21\1\23\1\21\1\24\2\21"+ - "\1\25\1\21\1\22\3\21\1\22\3\21\1\24\2\21"+ + "\1\25\1\21\1\22\3\21\1\22\3\21\1\26\2\21"+ "\1\25\1\21\1\22\2\21\1\12\1\13\3\12\1\14"+ - "\2\12\1\17\1\12\1\13\1\16\1\12\25\0\1\26"+ - "\13\0\1\27\1\30\5\0\1\13\10\0\1\13\5\0"+ - "\1\31\20\0\1\27\1\15\11\0\2\32\11\0\1\33"+ - "\12\0\1\22\10\0\1\22\4\0\3\23\13\0\1\34"+ - "\21\0\1\35\6\0\3\31\1\0\1\36\10\0\2\33"+ - "\13\0\3\34\1\0\1\37\6\0\5\40\1\0\6\40"+ - "\1\0"; + "\2\12\1\17\1\12\1\13\1\16\1\12\25\0\1\27"+ + "\13\0\1\30\1\31\5\0\1\13\10\0\1\13\5\0"+ + "\1\32\20\0\1\30\1\15\11\0\2\33\11\0\1\34"+ + "\12\0\1\22\10\0\1\22\4\0\3\23\13\0\1\35"+ + "\14\0\1\36\21\0\1\37\6\0\3\32\1\0\1\40"+ + "\10\0\2\34\13\0\3\35\1\0\1\41\10\0\3\36"+ + "\1\0\1\42\6\0\5\43\1\0\6\43\1\0"; private static int [] zzUnpackTrans() { - int [] result = new int[286]; + int [] result = new int[312]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -231,11 +232,11 @@ class _KDocLexer implements FlexLexer { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\6\0\1\11\2\1\1\11\6\1\1\11\4\1\1\0"+ - "\1\11\2\0\1\11\1\1\1\0\1\11\1\0\2\11"; + "\6\0\1\11\2\1\1\11\6\1\1\11\5\1\1\0"+ + "\1\11\2\0\1\11\1\1\2\0\1\11\1\0\3\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[32]; + int [] result = new int[35]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -567,7 +568,7 @@ class _KDocLexer implements FlexLexer { yybegin(tag != null && tag.isReferenceRequired() ? TAG_BEGINNING : TAG_TEXT_BEGINNING); return KDocTokens.TAG_NAME; } - case 14: break; + case 15: break; case 3: { if (yytextContainLineBreaks()) { yybegin(LINE_BEGINNING); @@ -577,65 +578,70 @@ class _KDocLexer implements FlexLexer { return KDocTokens.TEXT; // internal white space } } - case 15: break; + case 16: break; case 11: { yybegin(CONTENTS_BEGINNING); return KDocTokens.START; } - case 16: break; + case 17: break; case 8: { if (isLastToken()) return KDocTokens.END; else return KDocTokens.TEXT; } - case 17: break; + case 18: break; case 5: { yybegin(CONTENTS); return KDocTokens.TEXT; } - case 18: break; + case 19: break; + case 12: + { yybegin(TAG_TEXT_BEGINNING); + return KDocTokens.MARKDOWN_LINK; + } + case 20: break; + case 7: + { yybegin(TAG_TEXT_BEGINNING); + return KDocTokens.MARKDOWN_LINK; + } + case 21: break; case 6: { if (yytextContainLineBreaks()) { yybegin(LINE_BEGINNING); } return TokenType.WHITE_SPACE; } - case 19: break; - case 13: + case 22: break; + case 14: // lookahead expression with fixed lookahead length yypushback(1); { yybegin(CONTENTS); return KDocTokens.MARKDOWN_LINK; } - case 20: break; - case 12: + case 23: break; + case 13: { yybegin(CONTENTS); return KDocTokens.MARKDOWN_LINK; } - case 21: break; + case 24: break; case 1: { return TokenType.BAD_CHARACTER; } - case 22: break; + case 25: break; case 9: { yybegin(CONTENTS); return KDocTokens.MARKDOWN_ESCAPED_CHAR; } - case 23: break; + case 26: break; case 2: { yybegin(CONTENTS); return KDocTokens.TEXT; } - case 24: break; - case 7: - { yybegin(CONTENTS); - return KDocTokens.MARKDOWN_LINK; - } - case 25: break; + case 27: break; case 4: { yybegin(CONTENTS_BEGINNING); return KDocTokens.LEADING_ASTERISK; } - case 26: break; + case 28: break; default: if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt index 20e36fb5ef4..4b354b479ce 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/api/KDoc.kt @@ -27,4 +27,5 @@ public trait KDoc : PsiComment { public fun getDefaultSection(): KDocSection public fun findSectionByName(name: String): KDocSection? public fun findSectionByTag(tag: KDocKnownTag): KDocSection? + public fun findSectionByTag(tag: KDocKnownTag, subjectName: String): KDocSection? } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt index e0adf734e73..a3432d48324 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocImpl.kt @@ -46,4 +46,9 @@ public class KDocImpl(buffer: CharSequence?) : LazyParseablePsiElement(KDocToken override fun findSectionByTag(tag: KDocKnownTag): KDocSection? = findSectionByName(tag.name().toLowerCase()) + + override fun findSectionByTag(tag: KDocKnownTag, subjectName: String): KDocSection? = + getChildrenOfType().firstOrNull { + it.getName() == tag.name().toLowerCase() && it.getSubjectName() == subjectName + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocSection.kt b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocSection.kt index b1eeaba5066..fe277082278 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocSection.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocSection.kt @@ -34,6 +34,9 @@ public class KDocSection(node: ASTNode) : KDocTag(node) { override fun getName(): String? = (getFirstChild() as? KDocTag)?.getName() + override fun getSubjectName(): String? = + (getFirstChild() as? KDocTag)?.getSubjectName() + override fun getContent(): String = (getFirstChild() as? KDocTag)?.getContent() ?: super.getContent() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocTag.kt b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocTag.kt index f4f097c38b9..7a3cc025176 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocTag.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocTag.kt @@ -44,7 +44,7 @@ public open class KDocTag(node: ASTNode) : KDocElementImpl(node) { * Returns the name of the entity documented by this tag (for example, the name of the parameter * for the @param tag), or null if this tag does not document any specific entity. */ - public fun getSubjectName(): String? = getSubjectLink()?.getLinkText() + public open fun getSubjectName(): String? = getSubjectLink()?.getLinkText() public fun getSubjectLink(): KDocLink? { val children = childrenAfterTagName() diff --git a/compiler/testData/psi/kdoc/ParamTag.txt b/compiler/testData/psi/kdoc/ParamTag.txt index 5b727c6b959..7b7433c7e2e 100644 --- a/compiler/testData/psi/kdoc/ParamTag.txt +++ b/compiler/testData/psi/kdoc/ParamTag.txt @@ -13,6 +13,7 @@ JetFile: ParamTag.kt KDOC_MARKDOWN_LINK KDOC_NAME PsiElement(IDENTIFIER)('a') - PsiElement(KDOC_TEXT)(' The description of a.') + PsiWhiteSpace(' ') + PsiElement(KDOC_TEXT)('The description of a.') PsiWhiteSpace('\n ') PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/compiler/testData/psi/kdoc/ParamTagAtStart.txt b/compiler/testData/psi/kdoc/ParamTagAtStart.txt index 21feff72191..08caf4c3ac4 100644 --- a/compiler/testData/psi/kdoc/ParamTagAtStart.txt +++ b/compiler/testData/psi/kdoc/ParamTagAtStart.txt @@ -11,5 +11,6 @@ JetFile: ParamTagAtStart.kt KDOC_MARKDOWN_LINK KDOC_NAME PsiElement(IDENTIFIER)('a') - PsiElement(KDOC_TEXT)(' this is a ') + PsiWhiteSpace(' ') + PsiElement(KDOC_TEXT)('this is a ') PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/compiler/testData/psi/kdoc/Sections.txt b/compiler/testData/psi/kdoc/Sections.txt index e9412e72e33..723fad9988a 100644 --- a/compiler/testData/psi/kdoc/Sections.txt +++ b/compiler/testData/psi/kdoc/Sections.txt @@ -16,7 +16,8 @@ JetFile: Sections.kt KDOC_MARKDOWN_LINK KDOC_NAME PsiElement(IDENTIFIER)('T') - PsiElement(KDOC_TEXT)(' a type parameter.') + PsiWhiteSpace(' ') + PsiElement(KDOC_TEXT)('a type parameter.') PsiWhiteSpace('\n ') PsiElement(KDOC_LEADING_ASTERISK)('*') PsiElement(KDOC_TEXT)(' ') @@ -34,6 +35,7 @@ JetFile: Sections.kt KDOC_MARKDOWN_LINK KDOC_NAME PsiElement(IDENTIFIER)('a') - PsiElement(KDOC_TEXT)(' a constructor parameter.') + PsiWhiteSpace(' ') + PsiElement(KDOC_TEXT)('a constructor parameter.') PsiWhiteSpace('\n ') PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocFinder.kt b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocFinder.kt index 539ccfd0959..323a024dd8d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocFinder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/kdoc/KDocFinder.kt @@ -16,14 +16,13 @@ package org.jetbrains.kotlin.idea.kdoc -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource -import org.jetbrains.kotlin.resolve.source.PsiSourceElement -import org.jetbrains.kotlin.psi.JetDeclaration -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor -import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag +import org.jetbrains.kotlin.kdoc.psi.api.KDoc +import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag +import org.jetbrains.kotlin.psi.JetDeclaration +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.resolve.source.PsiSourceElement object KDocFinder { fun findKDoc(declaration: DeclarationDescriptor): KDocTag? { @@ -44,6 +43,20 @@ object KDocFinder { } } + if (declaration is PropertyDescriptor) { + val containingClassDescriptor = declaration.getContainingDeclaration() as? ClassDescriptor + if (containingClassDescriptor != null) { + val classKDoc = findKDoc(containingClassDescriptor)?.getParentOfType(false) + if (classKDoc != null) { + val propertySection = classKDoc.findSectionByTag(KDocKnownTag.PROPERTY, + declaration.getName().asString()) + if (propertySection != null) { + return propertySection + } + } + } + } + if (declaration is CallableDescriptor) { for (baseDescriptor in declaration.getOverriddenDescriptors()) { val baseKDoc = findKDoc(baseDescriptor.getOriginal()) diff --git a/idea/testData/kdoc/finder/Property.kt b/idea/testData/kdoc/finder/Property.kt new file mode 100644 index 00000000000..1c36cd0157a --- /dev/null +++ b/idea/testData/kdoc/finder/Property.kt @@ -0,0 +1,4 @@ +/** + * @property xyzzy Doc for property xyzzy + */ +class Foo(val xyzzy: String) diff --git a/idea/tests/org/jetbrains/kotlin/idea/kdoc/KDocFinderTest.kt b/idea/tests/org/jetbrains/kotlin/idea/kdoc/KDocFinderTest.kt index 8005c2e6830..6fd80b7edd2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/kdoc/KDocFinderTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/kdoc/KDocFinderTest.kt @@ -55,4 +55,13 @@ public class KDocFinderTest() : LightPlatformCodeInsightFixtureTestCase() { val doc = KDocFinder.findKDoc(overriddenFunctionDescriptor) Assert.assertEquals("Doc for method xyzzy", doc!!.getContent()) } + + public fun testProperty() { + myFixture.configureByFile(getTestName(false) + ".kt") + val declaration = (myFixture.getFile() as JetFile).getDeclarations().single { it.getName() == "Foo" } + val descriptor = declaration.resolveToDescriptor() as ClassDescriptor + val propertyDescriptor = descriptor.getDefaultType().getMemberScope().getProperties(Name.identifier("xyzzy")).single() + val doc = KDocFinder.findKDoc(propertyDescriptor) + Assert.assertEquals("Doc for property xyzzy", doc!!.getContent()) + } }