change KDoc parsing so that space after parameter/section name is not included in tag content; support @property tag in KDocFinder

This commit is contained in:
Dmitry Jemerov
2015-03-05 20:06:04 +01:00
parent 69744c0550
commit 28ed30bcb3
12 changed files with 98 additions and 53 deletions
@@ -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;
}
@@ -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
* <a href="http://www.jflex.de/">JFlex</a> 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
* <tt>/Users/yole/jetbrains/kotlin/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex</tt>
*/
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;
@@ -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?
}
@@ -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<KDocSection>().firstOrNull {
it.getName() == tag.name().toLowerCase() && it.getSubjectName() == subjectName
}
}
@@ -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()
@@ -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()
+2 -1
View File
@@ -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)('*/')
@@ -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)('*/')
+4 -2
View File
@@ -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)('*/')
@@ -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<KDoc>(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())
+4
View File
@@ -0,0 +1,4 @@
/**
* @property xyzzy Doc for property xyzzy
*/
class Foo(val xyzzy: String)
@@ -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())
}
}