code review
This commit is contained in:
@@ -35,11 +35,11 @@ public interface KDocTokens {
|
||||
ILazyParseableElementType KDOC = new ILazyParseableElementType("KDoc", JetLanguage.INSTANCE) {
|
||||
@Override
|
||||
public ASTNode parseContents(ASTNode chameleon) {
|
||||
PsiElement parentElement = chameleon.getTreeParent().getPsi();
|
||||
Project project = parentElement.getProject();
|
||||
PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, new KDocLexer(), getLanguage(),
|
||||
chameleon.getText());
|
||||
PsiParser parser = new KDocParser();
|
||||
PsiElement parentElement = chameleon.getTreeParent().getPsi();
|
||||
Project project = parentElement.getProject();
|
||||
PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, new KDocLexer(), getLanguage(),
|
||||
chameleon.getText());
|
||||
PsiParser parser = new KDocParser();
|
||||
|
||||
return parser.parse(this, builder).getFirstChildNode();
|
||||
}
|
||||
@@ -67,11 +67,11 @@ public interface KDocTokens {
|
||||
ILazyParseableElementType MARKDOWN_LINK = new ILazyParseableElementType("KDOC_MARKDOWN_LINK", JetLanguage.INSTANCE) {
|
||||
@Override
|
||||
public ASTNode parseContents(ASTNode chameleon) {
|
||||
PsiElement parentElement = chameleon.getTreeParent().getPsi();
|
||||
Project project = parentElement.getProject();
|
||||
PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, new JetLexer(), getLanguage(),
|
||||
chameleon.getText());
|
||||
PsiParser parser = new KDocLinkParser();
|
||||
PsiElement parentElement = chameleon.getTreeParent().getPsi();
|
||||
Project project = parentElement.getProject();
|
||||
PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, new JetLexer(), getLanguage(),
|
||||
chameleon.getText());
|
||||
PsiParser parser = new KDocLinkParser();
|
||||
|
||||
return parser.parse(this, builder).getFirstChildNode();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.lexer.JetTokens
|
||||
*/
|
||||
class KDocLinkParser(): PsiParser {
|
||||
override fun parse(root: IElementType, builder: PsiBuilder): ASTNode {
|
||||
builder.setDebugMode(true)
|
||||
val rootMarker = builder.mark()
|
||||
if (builder.getTokenType() == JetTokens.LBRACKET) {
|
||||
builder.advanceLexer()
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
package org.jetbrains.kotlin.kdoc.psi.api;
|
||||
|
||||
import com.intellij.psi.PsiComment;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection;
|
||||
import org.jetbrains.kotlin.psi.JetDeclaration;
|
||||
|
||||
// Don't implement JetElement (or it will be treated as statement)
|
||||
public interface KDoc extends PsiComment {
|
||||
@Nullable
|
||||
JetDeclaration getOwner();
|
||||
@NotNull
|
||||
KDocSection getDefaultSection();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class KDocImpl(buffer: CharSequence?) : LazyParseablePsiElement(KDocToken
|
||||
|
||||
override fun getTokenType(): IElementType = JetTokens.DOC_COMMENT
|
||||
|
||||
override fun getOwner(): JetDeclaration = getParentOfType<JetDeclaration>(true)!!
|
||||
override fun getOwner(): JetDeclaration? = getParentOfType<JetDeclaration>(true)
|
||||
|
||||
override fun getDefaultSection(): KDocSection = getChildOfType<KDocSection>()!!
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class KDocLink(node: ASTNode) : JetElementImpl(node) {
|
||||
public fun getLinkTextRange(): TextRange {
|
||||
val text = getText()
|
||||
if (text.startsWith('[') && text.endsWith(']')) {
|
||||
return TextRange(1, text.length()-1)
|
||||
return TextRange(1, text.length() - 1)
|
||||
}
|
||||
return TextRange(0, text.length())
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ public class KDocName(node: ASTNode): JetElementImpl(node) {
|
||||
|
||||
public fun getQualifier(): KDocName? = getChildOfType()
|
||||
|
||||
/**
|
||||
* Returns the range within the element containing the name (in other words,
|
||||
* the range of the element excluding the qualifier and dot, if present).
|
||||
*/
|
||||
public fun getNameTextRange(): TextRange {
|
||||
val dot = getNode().findChildByType(JetTokens.DOT)
|
||||
val textRange = getTextRange()
|
||||
|
||||
@@ -54,9 +54,13 @@ public open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
|
||||
return null
|
||||
}
|
||||
|
||||
public val knownTag: KDocKnownTag?
|
||||
get() {
|
||||
val name = getName()
|
||||
return if (name != null) KDocKnownTag.findByTagName(name) else null
|
||||
}
|
||||
|
||||
private fun hasSubject(contentChildren: List<ASTNode>): Boolean {
|
||||
val name = getName()
|
||||
val knownTag = if (name != null) KDocKnownTag.findByTagName(name) else null
|
||||
if (knownTag?.isReferenceRequired() ?: false) {
|
||||
return contentChildren.firstOrNull()?.getElementType() == KDocElementTypes.KDOC_LINK;
|
||||
}
|
||||
@@ -69,7 +73,7 @@ public open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
|
||||
.dropWhile { it.getElementType() == TokenType.WHITE_SPACE }
|
||||
|
||||
/**
|
||||
* Returns the contents of this tag (all text following the tag name and the subject if present,
|
||||
* Returns the content of this tag (all text following the tag name and the subject if present,
|
||||
* with leading asterisks removed).
|
||||
*/
|
||||
public fun getContent(): String {
|
||||
|
||||
@@ -78,7 +78,7 @@ public class FunctionDescriptorUtil {
|
||||
public static JetScope getFunctionInnerScope(
|
||||
@NotNull JetScope outerScope,
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
RedeclarationHandler redeclarationHandler
|
||||
@NotNull RedeclarationHandler redeclarationHandler
|
||||
) {
|
||||
WritableScope parameterScope = new WritableScopeImpl(outerScope, descriptor, redeclarationHandler, "Function inner scope");
|
||||
ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter();
|
||||
|
||||
@@ -70,7 +70,7 @@ public final class JetScopeUtils {
|
||||
public static JetScope getPropertyDeclarationInnerScope(
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull JetScope outerScope,
|
||||
RedeclarationHandler redeclarationHandler
|
||||
@NotNull RedeclarationHandler redeclarationHandler
|
||||
) {
|
||||
return getPropertyDeclarationInnerScope(propertyDescriptor,
|
||||
outerScope,
|
||||
@@ -119,7 +119,7 @@ public final class JetScopeUtils {
|
||||
@NotNull JetScope outerScope,
|
||||
@NotNull List<? extends TypeParameterDescriptor> typeParameters,
|
||||
@Nullable ReceiverParameterDescriptor receiver,
|
||||
RedeclarationHandler redeclarationHandler,
|
||||
@NotNull RedeclarationHandler redeclarationHandler,
|
||||
boolean addLabelForProperty
|
||||
) {
|
||||
WritableScopeImpl result = new WritableScopeImpl(
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* [A.B.C...]
|
||||
* [....]
|
||||
* [A..B..C]
|
||||
* [A.]
|
||||
*/
|
||||
@@ -0,0 +1,57 @@
|
||||
JetFile: MarkdownLinkWithError.kt
|
||||
PACKAGE_DIRECTIVE
|
||||
<empty list>
|
||||
KDoc
|
||||
PsiElement(KDOC_START)('/**')
|
||||
PsiWhiteSpace('\n ')
|
||||
KDOC_SECTION
|
||||
PsiElement(KDOC_LEADING_ASTERISK)('*')
|
||||
PsiElement(KDOC_TEXT)(' ')
|
||||
KDOC_LINK
|
||||
KDOC_MARKDOWN_LINK
|
||||
PsiElement(LBRACKET)('[')
|
||||
KDOC_NAME
|
||||
KDOC_NAME
|
||||
KDOC_NAME
|
||||
PsiElement(IDENTIFIER)('A')
|
||||
PsiElement(DOT)('.')
|
||||
PsiElement(IDENTIFIER)('B')
|
||||
PsiElement(DOT)('.')
|
||||
PsiElement(IDENTIFIER)('C')
|
||||
PsiErrorElement:Closing bracket expected
|
||||
<empty list>
|
||||
PsiElement(RANGE)('..')
|
||||
PsiElement(DOT)('.')
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiElement(KDOC_LEADING_ASTERISK)('*')
|
||||
PsiElement(KDOC_TEXT)(' [....]')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiElement(KDOC_LEADING_ASTERISK)('*')
|
||||
PsiElement(KDOC_TEXT)(' ')
|
||||
KDOC_LINK
|
||||
KDOC_MARKDOWN_LINK
|
||||
PsiElement(LBRACKET)('[')
|
||||
KDOC_NAME
|
||||
PsiElement(IDENTIFIER)('A')
|
||||
PsiErrorElement:Closing bracket expected
|
||||
<empty list>
|
||||
PsiElement(RANGE)('..')
|
||||
PsiElement(IDENTIFIER)('B')
|
||||
PsiElement(RANGE)('..')
|
||||
PsiElement(IDENTIFIER)('C')
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiElement(KDOC_LEADING_ASTERISK)('*')
|
||||
PsiElement(KDOC_TEXT)(' ')
|
||||
KDOC_LINK
|
||||
KDOC_MARKDOWN_LINK
|
||||
PsiElement(LBRACKET)('[')
|
||||
KDOC_NAME
|
||||
PsiElement(IDENTIFIER)('A')
|
||||
PsiElement(DOT)('.')
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiElement(RBRACKET)(']')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiElement(KDOC_END)('*/')
|
||||
@@ -1085,6 +1085,12 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest {
|
||||
doParsingTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MarkdownLinkWithError.kt")
|
||||
public void testMarkdownLinkWithError() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/kdoc/MarkdownLinkWithError.kt");
|
||||
doParsingTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MarkdownQualifiedName.kt")
|
||||
public void testMarkdownQualifiedName() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/kdoc/MarkdownQualifiedName.kt");
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
|
||||
|
||||
public class KDocReference(element: KDocName): JetMultiReference<KDocName>(element) {
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
@@ -54,7 +55,7 @@ public class KDocReference(element: KDocName): JetMultiReference<KDocName>(eleme
|
||||
if (declaration == null) {
|
||||
return arrayListOf()
|
||||
}
|
||||
val declarationDescriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
|
||||
val declarationDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
|
||||
val kdocLink = getElement().getStrictParentOfType<KDocLink>()!!
|
||||
return resolveKDocLink(session, declarationDescriptor, kdocLink.getTagIfSubject(), getElement().getQualifiedName())
|
||||
}
|
||||
@@ -75,7 +76,7 @@ public fun resolveKDocLink(session: KotlinCodeAnalyzer,
|
||||
fromDescriptor: DeclarationDescriptor,
|
||||
fromSubjectOfTag: KDocTag?,
|
||||
qualifiedName: List<String>): Collection<DeclarationDescriptor> {
|
||||
if (fromSubjectOfTag?.getName() == "param") {
|
||||
if (fromSubjectOfTag?.knownTag == KDocKnownTag.PARAM) {
|
||||
return resolveParamLink(fromDescriptor, qualifiedName)
|
||||
}
|
||||
|
||||
@@ -90,19 +91,20 @@ public fun resolveKDocLink(session: KotlinCodeAnalyzer,
|
||||
}
|
||||
|
||||
private fun resolveParamLink(fromDescriptor: DeclarationDescriptor, qualifiedName: List<String>): List<DeclarationDescriptor> {
|
||||
if (qualifiedName.size() != 1) {
|
||||
return listOf()
|
||||
}
|
||||
if (fromDescriptor is CallableDescriptor) {
|
||||
val valueParams = fromDescriptor.getValueParameters().filter { it.getName().asString() == qualifiedName[0] }
|
||||
if (valueParams.isNotEmpty()) {
|
||||
return valueParams
|
||||
}
|
||||
}
|
||||
if (fromDescriptor is ClassifierDescriptor) {
|
||||
val typeParams = fromDescriptor.getTypeConstructor().getParameters().filter { it.getName().asString() == qualifiedName[0] }
|
||||
if (typeParams.isNotEmpty()) {
|
||||
return typeParams
|
||||
// TODO resolve parameters of functions passed as parameters
|
||||
val name = qualifiedName.singleOrNull() ?: return listOf()
|
||||
when (fromDescriptor) {
|
||||
is CallableDescriptor ->
|
||||
return fromDescriptor.getValueParameters().filter { it.getName().asString() == name }
|
||||
is ClassifierDescriptor -> {
|
||||
val typeParams = fromDescriptor.getTypeConstructor().getParameters().filter { it.getName().asString() == name }
|
||||
if (typeParams.isNotEmpty()) {
|
||||
return typeParams
|
||||
}
|
||||
if (fromDescriptor is ClassDescriptor) {
|
||||
return resolveParamLink(fromDescriptor.getUnsubstitutedPrimaryConstructor(), qualifiedName)
|
||||
}
|
||||
return listOf()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +128,6 @@ private fun getClassInnerScope(outerScope: JetScope, descriptor: ClassDescriptor
|
||||
for (constructor in descriptor.getConstructors()) {
|
||||
headerScope.addFunctionDescriptor(constructor)
|
||||
}
|
||||
headerScope.addLabeledDeclaration(descriptor)
|
||||
headerScope.changeLockLevel(WritableScope.LockLevel.READING)
|
||||
|
||||
val classScope = ChainedScope(descriptor, "Class ${descriptor.getName()} scope", descriptor.getDefaultType().getMemberScope(), headerScope)
|
||||
@@ -134,30 +135,30 @@ private fun getClassInnerScope(outerScope: JetScope, descriptor: ClassDescriptor
|
||||
}
|
||||
|
||||
private fun getResolutionScope(session: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor): JetScope {
|
||||
when (descriptor) {
|
||||
return when (descriptor) {
|
||||
is PackageFragmentDescriptor ->
|
||||
return getPackageInnerScope(descriptor)
|
||||
getPackageInnerScope(descriptor)
|
||||
|
||||
is PackageViewDescriptor ->
|
||||
return descriptor.getMemberScope()
|
||||
descriptor.getMemberScope()
|
||||
|
||||
is ClassDescriptor ->
|
||||
return getClassInnerScope(getOuterScope(descriptor, session), descriptor)
|
||||
getClassInnerScope(getOuterScope(descriptor, session), descriptor)
|
||||
|
||||
is FunctionDescriptor ->
|
||||
return FunctionDescriptorUtil.getFunctionInnerScope(getOuterScope(descriptor, session),
|
||||
descriptor, RedeclarationHandler.DO_NOTHING)
|
||||
FunctionDescriptorUtil.getFunctionInnerScope(getOuterScope(descriptor, session),
|
||||
descriptor, RedeclarationHandler.DO_NOTHING)
|
||||
|
||||
is PropertyDescriptor ->
|
||||
return JetScopeUtils.getPropertyDeclarationInnerScope(descriptor,
|
||||
getOuterScope(descriptor, session),
|
||||
RedeclarationHandler.DO_NOTHING)
|
||||
JetScopeUtils.getPropertyDeclarationInnerScope(descriptor,
|
||||
getOuterScope(descriptor, session),
|
||||
RedeclarationHandler.DO_NOTHING)
|
||||
|
||||
is DeclarationDescriptorNonRoot ->
|
||||
getOuterScope(descriptor, session)
|
||||
|
||||
else -> throw IllegalArgumentException("Cannot find resolution scope for root $descriptor")
|
||||
}
|
||||
|
||||
if (descriptor is DeclarationDescriptorNonRoot)
|
||||
return getOuterScope(descriptor, session)
|
||||
|
||||
throw IllegalArgumentException("Cannot find resolution scope for root $descriptor")
|
||||
}
|
||||
|
||||
private fun getOuterScope(descriptor: DeclarationDescriptorWithSource, session: KotlinCodeAnalyzer): JetScope {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* This is [<caret>Foo]
|
||||
*/
|
||||
class Foo {
|
||||
}
|
||||
|
||||
// REF: (<root>).Foo
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @param <caret>i this is an integer
|
||||
*/
|
||||
class C(i: Int) {
|
||||
}
|
||||
|
||||
// REF: i
|
||||
@@ -17,9 +17,10 @@
|
||||
package org.jetbrains.kotlin.idea.kdoc;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.idea.resolve.AbstractReferenceResolveTest;
|
||||
import org.jetbrains.kotlin.test.InnerTestClasses;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.JetTestUtils;
|
||||
import org.jetbrains.kotlin.idea.resolve.AbstractReferenceResolveTest;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -36,12 +37,24 @@ public class KdocResolveTestGenerated extends AbstractReferenceResolveTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/kdoc/resolve"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ClassSelfReference.kt")
|
||||
public void testClassSelfReference() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/kdoc/resolve/ClassSelfReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("CodeReference.kt")
|
||||
public void testCodeReference() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/kdoc/resolve/CodeReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConstructorParamReference.kt")
|
||||
public void testConstructorParamReference() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/kdoc/resolve/ConstructorParamReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ImportedClassReference.kt")
|
||||
public void testImportedClassReference() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/kdoc/resolve/ImportedClassReference.kt");
|
||||
|
||||
Reference in New Issue
Block a user