checkers, annotators and dependencies moved to idea-analysis module

This commit is contained in:
Alexey Kudravtsev
2014-08-13 13:27:04 +04:00
parent a83d9a7dce
commit eb5f1a9953
133 changed files with 929 additions and 631 deletions
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin;
import com.intellij.CommonBundle;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.PropertyKey;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.ResourceBundle;
public class JetBundle {
private static Reference<ResourceBundle> ourBundle;
@NonNls
private static final String BUNDLE = "org.jetbrains.jet.plugin.JetBundle";
private JetBundle() {
}
@NotNull
public static String message(@NonNls @PropertyKey(resourceBundle = BUNDLE)String key, Object... params) {
return CommonBundle.message(getBundle(), key, params);
}
private static ResourceBundle getBundle() {
ResourceBundle bundle = null;
if (ourBundle != null) bundle = ourBundle.get();
if (bundle == null) {
bundle = ResourceBundle.getBundle(BUNDLE);
ourBundle = new SoftReference<ResourceBundle>(bundle);
}
return bundle;
}
}
@@ -0,0 +1,431 @@
#quick fix messages
add.function.body=Add function body
change.to.constructor.invocation=Change to constructor invocation
add.return.type=Add return type declaration
change.accessor.type=Change accessor type
change.getter.type=Change getter type to {0}
change.setter.type=Change setter parameter type to {0}
make.variable.immutable=Make variable immutable
make.variable.mutable=Make variable mutable
change.variable.mutability.family=Change Variable Mutability
remove.function.body=Remove function body
make.element.modifier=Make {0} {1}
add.modifier=Add ''{0}'' modifier
add.modifier.family=Add Modifier
make.element.in.classifiers.open=Make ''{0}'' in {1} open
make.class.annotation.class=Make ''{0}'' an annotation class
make.class.annotation.class.family=Make Class an Annotation Class
add.star.projections=Add ''{0}''
change.to.star.projection=Change type arguments to {0}
change.to.star.projection.family=Change to Star Projection
make.element.not.modifier=Make {0} not {1}
remove.modifier=Remove ''{0}'' modifier
remove.modifier.family=Remove Modifier
remove.redundant.modifier=Remove redundant ''{0}'' modifier
remove.parts.from.property=Remove {0} from property
remove.parts.from.property.family=Remove Parts from Property
remove.psi.element.family=Remove Element
remove.right.part.of.binary.expression=Remove right part of a binary expression
remove.cast=Remove cast
remove.elvis.operator=Remove elvis operator
remove.redundant.nullable=Remove redundant '?'
remove.supertype=Remove supertype ''{0}''
remove.supertype.family=Remove supertype
remove.supertype.nullable=Remove '?'
remove.type.arguments=Remove type arguments
remove.useless.nullable=Remove useless '?'
remove.nullable.family=Remove '?'
remove.spread.sign=Remove '*'
remove.useless.import=Remove useless import for ''{0}''
remove.useless.import.family=Remove Useless Import
replace.operation.in.binary.expression=Replace operation in a binary expression
replace.cast.with.static.assert=Replace a cast with a static assert
replace.with.dot.call=Replace with dot call
replace.with.safe.call=Replace with safe (?.) call
introduce.non.null.assertion=Add non-null asserted (!!) call
remove.unnecessary.non.null.assertion=Remove unnecessary non-null assertion (!!)
change.to.backing.field=Change reference to backing field
implement.members=Implement members
new.kotlin.file.action=Kotlin File
import.fix=Import
imports.chooser.title=Imports
specify.type.explicitly.action.family.name=Specify Type Explicitly
specify.type.explicitly.add.return.type.action.name=Specify return type explicitly
specify.type.explicitly.add.action.name=Specify type explicitly
specify.type.explicitly.remove.action.name=Remove explicitly specified type
convert.to.expression.body.action.family.name=Convert to Expression Body
convert.to.expression.body.action.name=Convert to expression body
convert.to.block.body.action.family.name=Convert to Block Body
convert.to.block.body.action.name=Convert to block body
rename.parameter.to.match.overridden.method=Rename parameter to match overridden method
rename.family=Rename
rename.kotlin.package.class.error="Can't rename kotlin package class"
add.semicolon.after.invocation=Add semicolon after invocation of ''{0}''
add.semicolon.family=Add Semicolon
change.function.return.type=Change ''{0}'' function return type to ''{1}''
change.no.name.function.return.type=Change function return type to ''{0}''
change.function.literal.return.type=Change function literal return type to ''{0}''
remove.function.return.type=Remove explicitly specified return type in ''{0}'' function
remove.no.name.function.return.type=Remove explicitly specified function return type
change.element.type=Change ''{0}'' type to ''{1}''
change.function.parameter.type=Change parameter ''{0}'' type of function ''{1}'' to ''{2}''
change.primary.constructor.parameter.type=Change parameter ''{0}'' type of primary constructor of class ''{1}'' to ''{2}''
change.type=Change type from ''{0}'' to ''{1}''
change.type.family=Change Type
add.parameters.to.function=Add parameter{0} to function ''{1}''
add.parameters.to.constructor=Add parameter{0} to constructor ''{1}''
change.function.signature=Change the signature of function ''{0}''
change.constructor.signature=Change the signature of constructor ''{0}''
change.function.literal.signature=Change the signature of function literal
remove.parameter=Remove parameter ''{0}''
change.signature.family=Change signature of function/constructor
cast.expression.to.type=Cast expression ''{0}'' to ''{1}''
cast.expression.family=Cast Expression
simplify.negated.binary.expression=Simplify negated ''{0}'' expression to ''{1}''
simplify.negated.binary.expression.family=Simplify Negated Binary Expression
replace.call.error.skipped.defaults=Cannot skip default arguments.
replace.call.error.undefined.returntype=Unable to determine the return type.
replace.call.error.duplicate.or.missing.arguments=Duplicate or missing arguments.
replace.call.error.invalid.arguments=Invalid arguments included.
replace.call.error.vararg.not.last=Cannot handle named arguments after a vararg.
replace.call.error.contains.returns_boolean=Contains must return a Boolean.
replace.get.with.index=Replace 'get' call with index operator
replace.get.with.index.family=Replace Get
replace.contains.with.in=Replace 'contains' call with in operator
replace.contains.with.in.family=Replace Contains
replace.invoke.with.call=Replace 'invoke' with direct call
replace.invoke.with.call.family=Replace Invoke
replace.unary.operator.with.prefix=Replace with ''{0}'' prefix
replace.unary.operator.with.prefix.family=Replace Unary Operator
replace.binary.operator.with.infix=Replace with ''{0}'' operator
replace.binary.operator.with.infix.family=Replace Binary Operator
add.kotlin.signature.action.family.name=Specify Custom Kotlin Signature
add.kotlin.signature.action.text=Specify custom Kotlin signature
edit.kotlin.signature.action.text=Edit custom Kotlin signature
view.kotlin.signature.action.text=View custom Kotlin signature
goto.super.function.chooser.title=Choose super function
goto.super.property.chooser.title=Choose super property
goto.super.class.chooser.title=Choose super class or interface
livetemplate.description.main=main() function
livetemplate.description.soutp=Prints function parameter names and values to System.out
livetemplate.description.iter=Iterate over elements of iterable
livetemplate.description.ifn=Inserts ''if null'' expression
livetemplate.description.inn=Inserts ''if not null'' expression
livetemplate.description.void=Function returning nothing
livetemplate.description.fun0=Function with no parameters
livetemplate.description.fun1=Function with one parameter
livetemplate.description.fun2=Function with two parameters
livetemplate.description.interface=Trait
livetemplate.description.singleton=Singleton
livetemplate.description.closure=Closure (function without name)
livetemplate.description.anonymous=Anonymous class
livetemplate.description.exfun=Extension function
livetemplate.description.exval=Extension read-only property
livetemplate.description.exvar=Extension read-write property
macro.variable.of.type=kotlinVariable()
macro.iterable.variable=kotlinIterableVariable()
macro.suggest.variable.name=kotlinSuggestVariableName()
macro.fun.parameters=functionParameters()
macro.fun.anonymousSuper=anonymousSuper()
change.visibility.modifier=Change visibility modifier
options.kotlin.attribute.descriptor.builtin.annotation=Built-in annotation
options.kotlin.attribute.descriptor.string.escape=Escape in string and template braces
options.kotlin.attribute.descriptor.closure.braces=Function literal braces and arrow
options.kotlin.attribute.descriptor.safe.access=Safe access dot
options.kotlin.attribute.descriptor.arrow=Arrow
options.kotlin.attribute.descriptor.kdoc.comment=KDoc comment
options.kotlin.attribute.descriptor.kdoc.tag=KDoc tag
options.kotlin.attribute.descriptor.kdoc.value=KDoc tag value
options.kotlin.attribute.descriptor.trait=Trait
options.kotlin.attribute.descriptor.object=Object
options.kotlin.attribute.descriptor.annotation=Annotation
options.kotlin.attribute.descriptor.var=Var (mutable variable, parameter or property)
options.kotlin.attribute.descriptor.local.variable=Local variable or value
options.kotlin.attribute.descriptor.captured.variable=Variables and values captured in a closure
options.kotlin.attribute.descriptor.instance.property=Instance property
options.kotlin.attribute.descriptor.package.property=Package-level property
options.kotlin.attribute.descriptor.property.with.backing=Property with backing field
options.kotlin.attribute.descriptor.backing.field.access=Backing field access
options.kotlin.attribute.descriptor.extension.property=Extension property
options.kotlin.attribute.descriptor.it=Function literal default parameter
options.kotlin.attribute.descriptor.fun=Function declaration
options.kotlin.attribute.descriptor.fun.call=Function call
options.kotlin.attribute.descriptor.package.fun.call=Package-level function call
options.kotlin.attribute.descriptor.extension.fun.call=Extension function call
options.kotlin.attribute.descriptor.constructor.call=Constructor call
options.kotlin.attribute.descriptor.variable.as.function.call=Variable as function call
options.kotlin.attribute.descriptor.variable.as.function.like.call=Variable as function-like call
options.kotlin.attribute.descriptor.auto.casted=Smart-cast value
options.kotlin.attribute.descriptor.label=Label
change.to.function.invocation=Change to function invocation
migrate.sure=Replace sure() calls by !! in project
remove.val.var.from.parameter=Remove val/var from function, loop and catch parameters in project
add.override.to.equals.hashCode.toString=Add 'override' to equals, hashCode, toString in project
add.when.else.branch.action.family.name=Add Else Branch
add.when.else.branch.action=Add else branch
move.when.else.branch.to.the.end.action=Move else branch to the end
move.when.else.branch.to.the.end.family.name=Move Else Branch to the End
change.to.property.name.family.name=Change to property name
change.to.property.name.action=Change ''{0}'' to ''{1}''
map.platform.class.to.kotlin=Change all usages of ''{0}'' in this file to ''{1}''
map.platform.class.to.kotlin.multiple=Change all usages of ''{0}'' in this file to a Kotlin class
map.platform.class.to.kotlin.advertisement=Choose an appropriate Kotlin class
map.platform.class.to.kotlin.family=Change to Kotlin class
create.from.usage.family=Create from usage
create.function.from.usage=Create function ''{0}'' from usage
choose.target.class.or.trait.title=Choose target class or trait
surround.with=Surround with
surround.with.string.template="${expr}"
surround.with.when.template=when (expr) {}
surround.with.function.template={ }
surround.with.cannot.perform.action=Cannot perform Surround With action to the current contextsurround.with.function.template={ }
remove.variable.family.name=Remove variable
remove.variable.action=Remove variable ''{0}''
kotlin.code.transformations=Kotlin Code Transformations
fold.if.to.assignment=Replace 'if' expression with assignment
fold.if.to.assignment.family=Replace 'if' Expression with Assignment
fold.if.to.return=Replace 'if' expression with return
fold.if.to.return.family=Replace 'if' Expression with Return
fold.if.to.call=Replace 'if' expression with method call
fold.if.to.call.family=Replace 'if' Expression with Method Call
fold.when.to.assignment=Replace 'when' expression with assignment
fold.when.to.assignment.family=Replace 'when' Expression with Assignment
fold.when.to.return=Replace 'when' expression with return
fold.when.to.return.family=Replace 'when' Expression with Return
fold.when.to.call=Replace 'when' expression with method call
fold.when.to.call.family=Replace 'when' Expression with Method Call
unfold.assignment.to.if=Replace assignment with 'if' expression
unfold.assignment.to.if.family=Replace Assignment with 'if' Expression
unfold.property.to.if=Replace property initializer with 'if' expression
unfold.property.to.if.family=Replace Property Initializer with 'if' Expression
unfold.return.to.if=Replace return with 'if' expression
unfold.return.to.if.family=Replace Return with 'if' Expression
unfold.call.to.if=Replace method call with 'if' expression
unfold.call.to.if.family=Replace Method Call with 'if' Expression
unfold.assignment.to.when=Replace assignment with 'when' expression
unfold.assignment.to.when.family=Replace Assignment with 'when' Expression
unfold.property.to.when=Replace property initializer with 'when' expression
unfold.property.to.when.family=Replace Property Initializer with 'when' Expression
unfold.return.to.when=Replace return with 'when' expression
unfold.return.to.when.family=Replace Return with 'when' Expression
unfold.call.to.when=Replace method call with 'when' expression
unfold.call.to.when.family=Replace Method Call with 'when' Expression
double.bang.to.if.then.exception.text=Expression ''{0}'' must not be null
double.bang.to.if.then.choose.exception=Choose Exception Class
double.bang.to.if.then=Replace '!!' expression with 'if' expression
double.bang.to.if.then.family=Replace '!!' Expression with 'if' Expression
if.then.to.double.bang=Replace 'if' expression with '!!' expression
if.then.to.double.bang.replace.exception=Replace 'if' expression with '!!' expression (will remove Exception)
if.then.to.double.bang.family=Replace 'if' Expression with '!!' Expression
elvis.to.if.then=Replace elvis expression with 'if' expression
elvis.to.if.then.family=Replace Elvis Expression with 'if' Expression
if.then.to.elvis=Replace 'if' expression with elvis expression
if.then.to.elvis.family=Replace 'if' Expression with Elvis Expression
safe.access.to.if.then=Replace safe access expression with 'if' expression
safe.access.to.if.then.family=Replace Safe Access Expression with 'if' Expression
if.then.to.safe.access=Replace 'if' expression with safe access expression
if.then.to.safe.access.family=Replace 'if' Expression with Safe Access Expression
if.to.when=Replace 'if' with 'when'
if.to.when.family=Replace 'if' with 'when'
when.to.if=Replace 'when' with 'if'
when.to.if.family=Replace 'when' with 'if'
flatten.when=Flatten 'when' expression
flatten.when.family=Flatten 'when' Expression
merge.when=Merge 'when' expressions
merge.when.family=Merge 'when' Expression
introduce.when.subject=Introduce argument to 'when'
introduce.when.subject.family=Introduce Argument to 'when'
eliminate.when.subject=Eliminate argument of 'when'
eliminate.when.subject.family=Eliminate Argument of 'when'
transform.if.statement.with.assignments.to.expression=Transform 'if' statement with assignments to expression
transform.assignment.with.if.expression.to.statement=Transform assignment with 'if' expression to statement
transform.if.statement.with.assignments.to.expression.family=Transform 'if' Statement with Assignments to Expression
transform.assignment.with.if.expression.to.statement.family=Transform Assignment with 'if' Expression to Statement
split.property.declaration=Split property declaration
split.property.declaration.family=Split Property Declaration
change.function.signature.action.single=Change function signature to ''{0}''
change.function.signature.action.multiple=Change function signature...
change.function.signature.family=Change function signature
change.function.signature.chooser.title=Choose signature
change.function.signature.action=Change function signature
remove.unnecessary.parentheses=Remove unnecessary parentheses
remove.unnecessary.parentheses.family=Remove Unnecessary Parentheses
remove.unnecessary.curly.brackets.from.string.template=Remove curly braces from variable
remove.unnecessary.curly.brackets.from.string.template.family=Remove Curly Braces From Variable
insert.curly.brackets.to.string.template=Insert curly braces around variable
insert.curly.brackets.to.string.template.family=Insert Curly Braces Around Variable
swap.binary.expression=Flip binary expression
swap.binary.expression.family=Flip Binary Expression
add.name.to.argument.family=Add Name to Argument
add.name.to.argument.single=Add name to argument\: ''{0}''
add.name.to.argument.multiple=Add name to argument...
add.name.to.argument.action=Add name to argument...
add.name.to.parameter.name.chooser.title=Choose parameter name
replace.with.dot.qualified.method.call.intention=Replace with simple method call
replace.with.dot.qualified.method.call.intention.family=Replace with Simple Method Call
replace.with.infix.function.call.intention=Replace with infix function call
replace.with.infix.function.call.intention.family=Replace with Infix Function Call
replace.with.infix.function.call.intention.error.resolution.failed=The element cannot be resolved
replace.with.infix.function.call.intention.error.package.call=Cannot be applied with a package as the receiver
replace.explicit.function.literal.param.with.it=Replace explicit parameter ''{0}'' with ''it''
replace.explicit.function.literal.param.with.it.family=Replace Explicit Parameter with 'it'
move.lambda.inside.parentheses=Move lambda function into parentheses
move.lambda.inside.parentheses.family=Move Lambda Function Into Parentheses
move.lambda.outside.parentheses=Move lambda expression out of parentheses
move.lambda.outside.parentheses.family=Move Lambda Expression out of Parentheses
replace.it.with.explicit.function.literal.param=Replace 'it' with explicit parameter
replace.it.with.explicit.function.literal.param.family=Replace 'it' with Explicit Parameter
remove.braces=Remove braces
remove.braces.family=Remove Braces
add.braces=Add braces
add.braces.family=Add Braces
convert.negated.boolean.sequence=Replace negated sequence with DeMorgan equivalent
convert.negated.boolean.sequence.family=Replace Negated Sequence with DeMorgan Equivalent
convert.negated.expression.with.demorgans.law=DeMorgan Law
convert.negated.expression.with.demorgans.law.andToOr=Replace '\\&\\&' with '||'
convert.negated.expression.with.demorgans.law.orToAnd=Replace '||' with '\\&\\&'
convert.negated.expression.with.demorgans.law.family=DeMorgan Law
split.if=Split into 2 if's
split.if.family=Split If
replace.with.operator.assign.intention=Replace with an operator-assign expression
replace.with.operator.assign.intention.family=Replace with an Operator-Assign Expression
replace.with.traditional.assignment.intention=Replace with traditional assignment
replace.with.traditional.assignment.intention.family=Replace with Traditional Assignment
simplify.boolean.with.constants=Simplify boolean expression
simplify.boolean.with.constants.family=Simplify Boolean Expression
insert.explicit.type.arguments=Add explicit type arguments
insert.explicit.type.arguments.family=Add Explicit Type Arguments
remove.explicit.type.arguments=Remove explicit type arguments
remove.explicit.type.arguments.family=Remove Explicit Type Arguments
convert.assert.to.if.with.throw=Replace 'assert' with 'if' statement
convert.assert.to.if.with.throw.family=Replace 'assert' with 'if' Statement
convert.if.with.throw.to.assert=Replace 'if' with 'assert' statement
convert.if.with.throw.to.assert.family=Replace 'if' with 'assert' Statement
make.type.explicit.in.lambda=Make types explicit in lambda
make.type.explicit.in.lambda.family=Make Types Explicit In Lambda
make.type.implicit.in.lambda=Make types implicit in lambda (may break code)
make.type.implicit.in.lambda.family=Make Types Implicit In Lambda (May Break Code)
invert.if.condition=Invert If Condition
invert.if.condition.family=Invert If Condition
operator.to.function=Replace overloaded operator with function call
operator.to.function.family=Replace Overloaded Operator With Function Call
convert.to.for.each.loop.intention=Replace with a for each loop
convert.to.for.each.loop.intention.family=Replace with a For Each Loop
convert.to.for.each.function.call.intention=Replace with a forEach function call
convert.to.for.each.function.call.intention.family=Replace with a forEach Function Call
convert.to.string.template=Convert concatenation to template
convert.to.string.template.family=Convert Concatenation to Template
convert.to.concatenated.string.intention=Convert template to concatenated string
convert.to.concatenated.string.intention.family=Convert Template to Concatenated String
property.is.implemented.too.many=Has implementations
property.is.overridden.too.many=Is overridden in subclasses
property.is.implemented.header=Is implemented in <br/>
property.is.overridden.header=Is overridden in <br/>
navigation.title.overriding.property=Choose Implementation of {0}
navigation.findUsages.title.overriding.property=Overriding properties of {0}
add.function.to.supertype.family=Add Function to Supertype
add.function.to.supertype.action.multiple=Add function to supertype...
add.function.to.type.action.single=Add ''{0}'' to ''{1}''
add.function.to.type.action=Add function to type
add.function.to.type.action.type.chooser=Choose type...
remove.expression = Remove ''{0}''
unwrap.expression = Unwrap ''{0}''
remove.else = Remove else in ''{0}''
unwrap.else = Unwrap else in ''{0}''
usageType.annotation.type = Annotation
usageType.import = Import directive
usageType.callable.reference = Callable reference
usageType.type.constraint = Type constraint
usageType.type.argument = Type argument
usageType.value.parameter.type = Parameter type
usageType.nonLocal.property.type = Class/object property type
usageType.local.variable.type = Local variable type
usageType.function.return.type = Function return types
usageType.superType = Supertype
usageType.type.definition = Type definition
usageType.is = Target type of 'is' operation
usageType.as = Target type of 'as' operation
usageType.class.object = Nested class/object
usageType.instantiation = Instantiation
usageType.function.call = Function call
usageType.implicit.get = Implicit 'get'
usageType.implicit.set = Implicit 'set'
usageType.implicit.invoke = Implicit 'invoke'
usageType.implicit.iteration = Implicit iteration
usageType.extension.receiver.type = Extension receiver type
usageType.super.type.qualifier = Super type qualifier
usageType.receiver = Receiver
usageType.selector = Selector
usageType.delegate = Delegate
usageType.packageDirective = Package directive
usageType.packageMemberAccess = Package member access
x.in.y={0} in {1}
x.implements.y={0} in {1} implements {2} in {3}.
x.overrides.y.in.class.list={0} in {1} overrides functions in the following classes/traits: {2} Do you want to {3} the base functions?
unused.overriding.methods.title=Unused Overriding Members
there.are.unused.methods.that.override.methods.you.delete=There are unused members that override methods you delete.
choose.the.ones.you.want.to.be.deleted=Choose the ones you want to be deleted.
method.column=Member
delete.param.in.method.hierarchy={0} is a part of method hierarchy. Do you want to delete multiple parameters?
super.methods.delete.with.usage.search=delete (with usage search)
super.methods.action.key.find.usages=find usages of
find.what.implementing.methods.checkbox=&Implementing functions
find.what.overriding.methods.checkbox=Over&riding functions
find.what.implementing.properties.checkbox=&Implementing properties
find.what.overriding.properties.checkbox=Over&riding properties
find.what.property.readers.checkbox=Readers
find.what.property.writers.checkbox=Writers
find.options.include.overloaded.methods.checkbox=Include o&verloaded functions and extensions
find.what.functions.usages.checkbox=Usages of &functions
find.what.properties.usages.checkbox=Usages of &properties
find.what.constructor.usages.checkbox=Usages of &constructor
find.what.derived.traits.checkbox=&Derived traits
find.what.derived.classes.checkbox=&Derived classes
hierarchy.legend.member.is.defined.in.class=Member is defined in the class
hierarchy.legend.member.defined.in.superclass=Member is not defined in the class but defined in superclass
hierarchy.legend.member.should.be.defined=Member should be defined since the class is not abstract
convert.to.extension=Convert to extension
replace.by.reconstructed.type.family.name=Replace by Reconstructed Type
replace.by.reconstructed.type=Replace by ''{0}''
suppress.warnings.family=Suppress Warnings
suppress.warning.for=Suppress ''{0}'' for {1} {2}
# Kotlin Compiler Settings Tab
#Common
kotlin.compiler.option.generate.no.warnings=Generate no &warnings
kotlin.compiler.option.additional.command.line.parameters=&Additional command line parameters:
kotlin.compiler.option.additional.command.line.parameters.dialog.title=Additional command line parameters
# Kotlin to JVM
kotlin.compiler.jvm.option.panel.title=Kotlin to JVM
# Kotlin to JavaScript
kotlin.compiler.js.option.panel.title=Kotlin to JavaScript
kotlin.compiler.js.option.generate.sourcemaps=Generate &source maps
kotlin.compiler.js.option.output.prefix=Output file &prefix:
kotlin.compiler.js.option.output.postfix=Output file p&ostfix:
kotlin.compiler.js.option.output.prefix.browse.title=Choose output file prefix
kotlin.compiler.js.option.output.postfix.browse.title=Choose output file postfix
@@ -0,0 +1,162 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin;
import com.intellij.ide.IconProvider;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.RowIcon;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.KotlinLightClassForExplicitDeclaration;
import org.jetbrains.jet.asJava.KotlinLightClassForPackage;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetTokens;
import javax.swing.*;
import java.util.List;
public class JetIconProvider extends IconProvider {
public static JetIconProvider INSTANCE = new JetIconProvider();
@Nullable
public static JetClassOrObject getMainClass(@NotNull JetFile file) {
List<JetDeclaration> classes = ContainerUtil.filter(file.getDeclarations(), new Condition<JetDeclaration>() {
@Override
public boolean value(JetDeclaration jetDeclaration) {
return jetDeclaration instanceof JetClassOrObject;
}
});
if (classes.size() == 1) {
if (StringUtil.getPackageName(file.getName()).equals(classes.get(0).getName())) {
return (JetClassOrObject) classes.get(0);
}
}
return null;
}
@Override
public Icon getIcon(@NotNull PsiElement psiElement, int flags) {
if (psiElement instanceof JetFile) {
JetFile file = (JetFile) psiElement;
JetClassOrObject mainClass = getMainClass(file);
return mainClass != null && file.getDeclarations().size() == 1 ? getIcon(mainClass, flags) : JetIcons.FILE;
}
Icon result = getBaseIcon(psiElement);
if ((flags & Iconable.ICON_FLAG_VISIBILITY) > 0 && psiElement instanceof JetModifierListOwner) {
JetModifierList list = ((JetModifierListOwner) psiElement).getModifierList();
if (list != null) {
result = createRowIcon(result, getVisibilityIcon(list));
}
}
return result;
}
private static RowIcon createRowIcon(Icon baseIcon, Icon visibilityIcon) {
RowIcon rowIcon = new RowIcon(2);
rowIcon.setIcon(baseIcon, 0);
rowIcon.setIcon(visibilityIcon, 1);
return rowIcon;
}
public static Icon getVisibilityIcon(JetModifierList list) {
if (list.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
return PlatformIcons.PRIVATE_ICON;
}
if (list.hasModifier(JetTokens.PROTECTED_KEYWORD)) {
return PlatformIcons.PROTECTED_ICON;
}
if (list.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
return PlatformIcons.PUBLIC_ICON;
}
return PlatformIcons.PACKAGE_LOCAL_ICON;
}
public static Icon getBaseIcon(PsiElement psiElement) {
if (psiElement instanceof JetPackageDirective) {
return PlatformIcons.PACKAGE_ICON;
}
if (psiElement instanceof KotlinLightClassForPackage) {
return JetIcons.FILE;
}
if (psiElement instanceof KotlinLightClassForExplicitDeclaration) {
psiElement = psiElement.getNavigationElement();
}
if (psiElement instanceof JetNamedFunction) {
if (((JetFunction) psiElement).getReceiverTypeRef() != null) {
return JetIcons.EXTENSION_FUNCTION;
}
if (PsiTreeUtil.getParentOfType(psiElement, JetNamedDeclaration.class) instanceof JetClass) {
if (JetPsiUtil.isAbstract((JetFunction) psiElement)) {
return PlatformIcons.ABSTRACT_METHOD_ICON;
}
else {
return PlatformIcons.METHOD_ICON;
}
}
else {
return JetIcons.FUNCTION;
}
}
if (psiElement instanceof JetFunctionLiteral) return JetIcons.LAMBDA;
if (psiElement instanceof JetClass) {
JetClass jetClass = (JetClass) psiElement;
if (jetClass.isTrait()) {
return JetIcons.TRAIT;
}
Icon icon = jetClass.isEnum() ? JetIcons.ENUM : JetIcons.CLASS;
if (jetClass instanceof JetEnumEntry) {
JetEnumEntry enumEntry = (JetEnumEntry) jetClass;
if (enumEntry.getPrimaryConstructorParameterList() == null) {
icon = JetIcons.ENUM;
}
}
return icon;
}
if (psiElement instanceof JetObjectDeclaration || psiElement instanceof JetClassObject) {
return JetIcons.OBJECT;
}
if (psiElement instanceof JetParameter) {
JetParameter parameter = (JetParameter) psiElement;
if (JetPsiUtil.getClassIfParameterIsProperty(parameter) != null) {
return parameter.isMutable() ? JetIcons.FIELD_VAR : JetIcons.FIELD_VAL;
}
return JetIcons.PARAMETER;
}
if (psiElement instanceof JetProperty) {
JetProperty property = (JetProperty) psiElement;
return property.isVar() ? JetIcons.FIELD_VAR : JetIcons.FIELD_VAL;
}
return null;
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin;
import com.intellij.openapi.util.IconLoader;
import com.intellij.util.PlatformIcons;
import javax.swing.*;
public interface JetIcons {
Icon SMALL_LOGO = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/kotlin.png");
Icon KOTLIN_LOGO_24 = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/kotlin24.png");
Icon SMALL_LOGO_13 = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/kotlin13.png");
Icon CLASS = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/classKotlin.png");
Icon ENUM = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/enumKotlin.png");
Icon FILE = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/kotlin_file.png");
Icon OBJECT = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/objectKotlin.png");
Icon TRAIT = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/traitKotlin.png");
Icon FUNCTION = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/function.png");
Icon EXTENSION_FUNCTION = PlatformIcons.FUNCTION_ICON;
Icon LAMBDA = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/lambda.png");
Icon VAR = PlatformIcons.VARIABLE_ICON;
Icon VAL = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/value.png");
Icon PARAMETER = PlatformIcons.PARAMETER_ICON;
Icon FIELD_VAL = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/field_value.png");
Icon FIELD_VAR = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/field_variable.png");
Icon LAUNCH = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/kotlin_launch_configuration.png");
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
public class ProjectRootsUtil {
public static boolean isInSource(@NotNull PsiElement element) {
return isInSource(element, true);
}
public static boolean isInSource(@NotNull PsiElement element, boolean includeLibrarySources) {
PsiFile containingFile = element.getContainingFile();
if (containingFile == null) {
return false;
}
VirtualFile virtualFile = containingFile.getVirtualFile();
if (virtualFile == null) {
return false;
}
ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(element.getProject());
return includeLibrarySources ? index.isInSource(virtualFile) : index.isInSourceContent(virtualFile);
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.actions.internal
import com.intellij.ide.util.PropertiesComponent
public class KotlinInternalMode {
public class object {
val INTERNAL_MODE_PROPERTY = "kotlin.internal.mode.enabled"
public var enabled: Boolean
get() = PropertiesComponent.getInstance()!!.getBoolean(
INTERNAL_MODE_PROPERTY,
System.getProperty(INTERNAL_MODE_PROPERTY) == "true"
)
set(value) {
PropertiesComponent.getInstance()!!.setValue(INTERNAL_MODE_PROPERTY, value.toString())
}
}
}
@@ -0,0 +1,191 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.caches;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.descriptors.serialization.*;
import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_CLASS;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_PACKAGE;
/**
* Number of helper methods for searching kotlin element prototypes in java. Methods use java indices for search.
*/
public class JetFromJavaDescriptorHelper {
private JetFromJavaDescriptorHelper() {
}
static Collection<PsiClass> getClassesForKotlinPackages(Project project, GlobalSearchScope scope) {
/* Will iterate through short name caches
Kotlin packages from jar a class files will be collected from java cache
Kotlin package classes from sources will be collected with JetShortNamesCache.getClassesByName */
return getClassesByAnnotation(KOTLIN_PACKAGE.shortName().asString(), project, scope);
}
/**
* Get names that could have jet descriptor equivalents. It could be inaccurate and return more results than necessary.
*/
static Collection<String> getPossiblePackageDeclarationsNames(Project project, GlobalSearchScope scope) {
Collection<String> result = new ArrayList<String>();
for (PsiClass packageClass : getClassesForKotlinPackages(project, scope)) {
for (PsiMethod psiMethod : packageClass.getMethods()) {
if (psiMethod.getModifierList().hasModifierProperty(PsiModifier.STATIC)) {
result.add(psiMethod.getName());
}
}
}
return result;
}
static Collection<PsiClass> getCompiledClassesForTopLevelObjects(Project project, GlobalSearchScope scope) {
Set<PsiClass> jetObjectClasses = Sets.newHashSet();
Collection<PsiClass> classesByAnnotation = getClassesByAnnotation(KOTLIN_CLASS.shortName().asString(), project, scope);
for (PsiClass psiClass : classesByAnnotation) {
ClassKind kind = getCompiledClassKind(psiClass);
if (kind == ClassKind.OBJECT && psiClass.getContainingClass() == null) {
jetObjectClasses.add(psiClass);
}
}
return jetObjectClasses;
}
@Nullable
public static ClassKind getCompiledClassKind(@NotNull PsiClass psiClass) {
ClassData classData = getClassData(psiClass);
if (classData == null) return null;
return SerializationPackage.classKind(Flags.CLASS_KIND.get(classData.getClassProto().getFlags()));
}
@Nullable
private static ClassData getClassData(@NotNull PsiClass psiClass) {
String[] data = getAnnotationDataForKotlinClass(psiClass);
return data == null ? null : JavaProtoBufUtil.readClassDataFrom(data);
}
@Nullable
private static PackageData getPackageData(@NotNull PsiClass psiClass) {
String[] data = getAnnotationDataForKotlinClass(psiClass);
return data == null ? null : JavaProtoBufUtil.readPackageDataFrom(data);
}
@Nullable
private static String[] getAnnotationDataForKotlinClass(@NotNull PsiClass psiClass) {
VirtualFile virtualFile = getVirtualFileForPsiClass(psiClass);
if (virtualFile != null) {
KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile);
if (kotlinClass != null) {
return kotlinClass.getClassHeader().getAnnotationData();
}
}
return null;
}
//TODO: common utility
//TODO: doesn't work for inner classes and stuff
@Nullable
private static VirtualFile getVirtualFileForPsiClass(@NotNull PsiClass psiClass) {
PsiFile psiFile = psiClass.getContainingFile();
return psiFile == null ? null : psiFile.getVirtualFile();
}
@Nullable
static FqName getJetTopLevelDeclarationFQN(@NotNull PsiMethod method) {
PsiClass containingClass = method.getContainingClass();
if (containingClass != null) {
String qualifiedName = containingClass.getQualifiedName();
assert qualifiedName != null;
FqName classFQN = new FqName(qualifiedName);
if (JavaResolverPsiUtils.isCompiledKotlinPackageClass(containingClass)) {
return classFQN.parent().child(Name.identifier(method.getName()));
}
}
return null;
}
private static Collection<PsiClass> getClassesByAnnotation(
String annotationName, Project project, GlobalSearchScope scope
) {
Collection<PsiClass> classes = Sets.newHashSet();
Collection<PsiAnnotation> annotations = JavaAnnotationIndex.getInstance().get(annotationName, project, scope);
for (PsiAnnotation annotation : annotations) {
PsiModifierList modifierList = (PsiModifierList) annotation.getParent();
PsiElement owner = modifierList.getParent();
if (owner instanceof PsiClass) {
classes.add((PsiClass) owner);
}
}
return classes;
}
@NotNull
public static Collection<FqName> getTopLevelFunctionFqNames(
@NotNull Project project,
@NotNull GlobalSearchScope scope,
boolean shouldBeExtension
) {
Collection<FqName> result = Sets.newHashSet();
Collection<PsiClass> packageClasses = getClassesByAnnotation(KOTLIN_PACKAGE.shortName().asString(), project, scope);
for (PsiClass psiClass : packageClasses) {
String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName == null) {
continue;
}
FqName packageFqName = new FqName(qualifiedName).parent();
PackageData data = getPackageData(psiClass);
if (data == null) {
continue;
}
NameResolver nameResolver = data.getNameResolver();
for (ProtoBuf.Callable callable : data.getPackageProto().getMemberList()) {
if (callable.hasReceiverType() == shouldBeExtension) {
Name name = nameResolver.getName(callable.getName());
result.add(packageFqName.child(name));
}
}
}
return result;
}
}
@@ -0,0 +1,443 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.caches;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.JavaElementFinder;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.ImportPath;
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
import org.jetbrains.jet.plugin.caches.resolve.IDELightClassGenerationSupport;
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
import org.jetbrains.jet.plugin.stubindex.*;
import java.util.*;
import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
import static org.jetbrains.jet.plugin.caches.JetFromJavaDescriptorHelper.getTopLevelFunctionFqNames;
/**
* Will provide both java elements from kotlin context and some declarations special to kotlin.
* All those declaration are planned to be used in completion.
*/
public class JetShortNamesCache extends PsiShortNamesCache {
@NotNull
public static JetShortNamesCache getKotlinInstance(@NotNull Project project) {
PsiShortNamesCache[] extensions = Extensions.getArea(project).getExtensionPoint(PsiShortNamesCache.EP_NAME).getExtensions();
for (PsiShortNamesCache extension : extensions) {
if (extension instanceof JetShortNamesCache) {
return (JetShortNamesCache) extension;
}
}
throw new IllegalStateException(JetShortNamesCache.class.getSimpleName() + " is not found for project " + project);
}
private static final PsiMethod[] NO_METHODS = new PsiMethod[0];
private static final PsiField[] NO_FIELDS = new PsiField[0];
private final Project project;
public JetShortNamesCache(Project project) {
this.project = project;
}
/**
* Return kotlin class names from project sources which should be visible from java.
*/
@NotNull
@Override
public String[] getAllClassNames() {
Collection<String> classNames = JetClassShortNameIndex.getInstance().getAllKeys(project);
// package classes can not be indexed, since they have no explicit declarations
IDELightClassGenerationSupport lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project);
Set<String> packageClassShortNames =
lightClassGenerationSupport.getAllPossiblePackageClasses(GlobalSearchScope.allScope(project)).keySet();
classNames.addAll(packageClassShortNames);
return ArrayUtil.toStringArray(classNames);
}
/**
* Return class names form kotlin sources in given scope which should be visible as Java classes.
*/
@NotNull
@Override
public PsiClass[] getClassesByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) {
List<PsiClass> result = new ArrayList<PsiClass>();
IDELightClassGenerationSupport lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project);
MultiMap<String, FqName> packageClasses = lightClassGenerationSupport.getAllPossiblePackageClasses(scope);
// package classes can not be indexed, since they have no explicit declarations
Collection<FqName> fqNames = packageClasses.get(name);
if (!fqNames.isEmpty()) {
for (FqName fqName : fqNames) {
PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope);
if (psiClass != null) {
result.add(psiClass);
}
}
}
// Quick check for classes from getAllClassNames()
Collection<JetClassOrObject> classOrObjects = JetClassShortNameIndex.getInstance().get(name, project, scope);
if (classOrObjects.isEmpty()) {
return result.toArray(new PsiClass[result.size()]);
}
for (JetClassOrObject classOrObject : classOrObjects) {
FqName fqName = classOrObject.getFqName();
if (fqName != null) {
assert fqName.shortName().asString().equals(name) : "A declaration obtained from index has non-matching name:\n" +
"in index: " + name + "\n" +
"declared: " + fqName.shortName() + "(" + fqName + ")";
PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope);
if (psiClass != null) {
result.add(psiClass);
}
}
}
return result.toArray(new PsiClass[result.size()]);
}
@Override
public void getAllClassNames(@NotNull HashSet<String> destination) {
destination.addAll(Arrays.asList(getAllClassNames()));
}
/**
* Get kotlin non-extension top-level function names. Method is allowed to give invalid names - all result should be
* checked with getTopLevelFunctionDescriptorsByName().
*
* @return
*/
@NotNull
public Collection<String> getAllTopLevelFunctionNames() {
Set<String> functionNames = new HashSet<String>();
functionNames.addAll(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project));
functionNames.addAll(JetFromJavaDescriptorHelper.getPossiblePackageDeclarationsNames(project, GlobalSearchScope.allScope(project)));
return functionNames;
}
@NotNull
public Collection<String> getAllTopLevelObjectNames() {
Set<String> topObjectNames = new HashSet<String>();
topObjectNames.addAll(JetTopLevelObjectShortNameIndex.getInstance().getAllKeys(project));
Collection<PsiClass> classObjects =
JetFromJavaDescriptorHelper.getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project));
topObjectNames.addAll(Collections2.transform(classObjects, new Function<PsiClass, String>() {
@Override
public String apply(@Nullable PsiClass aClass) {
assert aClass != null;
return aClass.getName();
}
}));
return topObjectNames;
}
@NotNull
public Collection<ClassDescriptor> getTopLevelObjectsByName(
@NotNull String name,
@NotNull JetSimpleNameExpression expression,
@NotNull ResolveSessionForBodies resolveSession,
@NotNull GlobalSearchScope scope
) {
BindingContext context = resolveSession.resolveToElement(expression);
JetScope jetScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
if (jetScope == null) {
return Collections.emptyList();
}
Set<ClassDescriptor> result = Sets.newHashSet();
Collection<JetObjectDeclaration> topObjects = JetTopLevelObjectShortNameIndex.getInstance().get(name, project, scope);
for (JetObjectDeclaration objectDeclaration : topObjects) {
FqName fqName = objectDeclaration.getFqName();
assert fqName != null : "Local object declaration in JetTopLevelShortObjectNameIndex:" + objectDeclaration.getText();
result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession, fqName, ResolveSessionUtils.SINGLETON_FILTER));
}
for (PsiClass psiClass : JetFromJavaDescriptorHelper
.getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project))) {
String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName != null) {
FqName fqName = new FqName(qualifiedName);
result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession, fqName, ResolveSessionUtils.SINGLETON_FILTER));
}
}
return result;
}
@NotNull
public Collection<FunctionDescriptor> getTopLevelFunctionDescriptorsByName(
@NotNull String name,
@NotNull JetSimpleNameExpression expression,
@NotNull ResolveSessionForBodies resolveSession,
@NotNull GlobalSearchScope scope
) {
// name parameter can differ from expression.getReferenceName() when expression contains completion suffix
final Name referenceName = expression.getIdentifier() == null ? JetPsiUtil.getConventionName(expression) : Name.identifier(name);
if (referenceName == null || referenceName.toString().isEmpty()) {
return Collections.emptyList();
}
BindingContext context = resolveSession.resolveToElement(expression);
JetScope jetScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
if (jetScope == null) {
return Collections.emptyList();
}
Set<FunctionDescriptor> result = Sets.newHashSet();
Collection<FqName> topLevelFunctionFqNames =
ContainerUtil.filter(getTopLevelFunctionFqNames(project, scope, false), new Condition<FqName>() {
@Override
public boolean value(FqName fqName) {
return fqName.lastSegmentIs(referenceName);
}
});
for (FqName fqName : topLevelFunctionFqNames) {
JetImportDirective importDirective = JetPsiFactory(expression).createImportDirective(new ImportPath(fqName, false));
Collection<? extends DeclarationDescriptor> declarationDescriptors = new QualifiedExpressionResolver().analyseImportReference(
importDirective, jetScope, new BindingTraceContext(), resolveSession.getModuleDescriptor());
for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) {
if (declarationDescriptor instanceof FunctionDescriptor) {
result.add((FunctionDescriptor) declarationDescriptor);
}
}
}
Set<FqName> affectedPackages = Sets.newHashSet();
Collection<JetNamedFunction> jetNamedFunctions =
JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().get(referenceName.asString(), project, scope);
for (JetNamedFunction jetNamedFunction : jetNamedFunctions) {
PsiFile containingFile = jetNamedFunction.getContainingFile();
if (containingFile instanceof JetFile) {
JetFile jetFile = (JetFile) containingFile;
affectedPackages.add(jetFile.getPackageFqName());
}
}
for (FqName affectedPackage : affectedPackages) {
PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(affectedPackage);
assert packageDescriptor != null : "There's a function in stub index with invalid package: " + affectedPackage;
JetScope memberScope = packageDescriptor.getMemberScope();
result.addAll(memberScope.getFunctions(referenceName));
}
return result;
}
private Collection<PsiElement> getJetExtensionFunctionsByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
HashSet<PsiElement> functions = new HashSet<PsiElement>();
functions.addAll(JetTopLevelExtensionFunctionShortNameIndex.getInstance().get(name, project, scope));
return functions;
}
// TODO: Make it work for properties
@NotNull
public Collection<DeclarationDescriptor> getJetCallableExtensions(
@NotNull final Condition<String> acceptedNameCondition,
@NotNull JetSimpleNameExpression expression,
@NotNull ResolveSessionForBodies resolveSession,
@NotNull GlobalSearchScope searchScope
) {
BindingContext context = resolveSession.resolveToElement(expression);
JetExpression receiverExpression = PsiUtilPackage.getReceiverExpression(expression);
if (receiverExpression == null) {
return Collections.emptyList();
}
JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
JetScope scope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression);
if (expressionType == null || scope == null || expressionType.isError()) {
return Collections.emptyList();
}
Set<FqName> functionFQNs = extensionFunctionsFromSourceFqNames(acceptedNameCondition, searchScope);
functionFQNs.addAll(ContainerUtil.filter(getTopLevelFunctionFqNames(project, searchScope, true), new Condition<FqName>() {
@Override
public boolean value(FqName fqName) {
return acceptedNameCondition.value(fqName.shortName().asString());
}
}));
Collection<DeclarationDescriptor> resultDescriptors = new ArrayList<DeclarationDescriptor>();
// Iterate through the function with attempt to resolve found functions
for (FqName functionFQN : functionFQNs) {
for (CallableDescriptor functionDescriptor : ExpressionTypingUtils.canFindSuitableCall(
functionFQN, receiverExpression, expressionType, scope, resolveSession.getModuleDescriptor())) {
resultDescriptors.add(functionDescriptor);
}
}
return resultDescriptors;
}
@NotNull
private Set<FqName> extensionFunctionsFromSourceFqNames(
@NotNull Condition<String> acceptedNameCondition,
@NotNull GlobalSearchScope searchScope
) {
Set<String> extensionFunctionNames = new HashSet<String>(JetTopLevelExtensionFunctionShortNameIndex.getInstance().getAllKeys(project));
Set<FqName> functionFQNs = new java.util.HashSet<FqName>();
// Collect all possible extension function qualified names
for (String name : extensionFunctionNames) {
if (acceptedNameCondition.value(name)) {
Collection<PsiElement> extensionFunctions = getJetExtensionFunctionsByName(name, searchScope);
for (PsiElement extensionFunction : extensionFunctions) {
if (extensionFunction instanceof JetNamedFunction) {
functionFQNs.add(((JetNamedFunction) extensionFunction).getFqName());
}
else if (extensionFunction instanceof PsiMethod) {
FqName functionFQN =
JetFromJavaDescriptorHelper.getJetTopLevelDeclarationFQN((PsiMethod) extensionFunction);
if (functionFQN != null) {
functionFQNs.add(functionFQN);
}
}
}
}
}
return functionFQNs;
}
@NotNull
public Collection<ClassDescriptor> getJetClassesDescriptors(
@NotNull Condition<String> acceptedShortNameCondition,
@NotNull KotlinCodeAnalyzer analyzer,
@NotNull GlobalSearchScope searchScope
) {
Collection<ClassDescriptor> classDescriptors = new ArrayList<ClassDescriptor>();
for (String fqName : JetFullClassNameIndex.getInstance().getAllKeys(project)) {
FqName classFQName = new FqName(fqName);
if (acceptedShortNameCondition.value(classFQName.shortName().asString())) {
classDescriptors.addAll(getJetClassesDescriptorsByFQName(analyzer, classFQName, searchScope));
}
}
return classDescriptors;
}
private Collection<ClassDescriptor> getJetClassesDescriptorsByFQName(
@NotNull KotlinCodeAnalyzer analyzer, @NotNull FqName classFQName, @NotNull GlobalSearchScope searchScope) {
Collection<JetClassOrObject> jetClassOrObjects = JetFullClassNameIndex.getInstance().get(
classFQName.asString(), project, searchScope);
if (jetClassOrObjects.isEmpty()) {
// This fqn is absent in caches, dead or not in scope
return Collections.emptyList();
}
// Note: Can't search with psi element as analyzer could be built over temp files
return ResolveSessionUtils.getClassDescriptorsByFqName(analyzer, classFQName);
}
@NotNull
@Override
public PsiMethod[] getMethodsByName(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope) {
return NO_METHODS;
}
@NotNull
@Override
public PsiMethod[] getMethodsByNameIfNotMoreThan(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope, int maxCount) {
return NO_METHODS;
}
@NotNull
@Override
public PsiField[] getFieldsByNameIfNotMoreThan(@NonNls @NotNull String s, @NotNull GlobalSearchScope scope, int i) {
return NO_FIELDS;
}
@Override
public boolean processMethodsWithName(
@NonNls @NotNull String name,
@NotNull GlobalSearchScope scope,
@NotNull Processor<PsiMethod> processor
) {
return ContainerUtil.process(getMethodsByName(name, scope), processor);
}
@NotNull
@Override
public String[] getAllMethodNames() {
return ArrayUtil.EMPTY_STRING_ARRAY;
}
@Override
public void getAllMethodNames(@NotNull HashSet<String> set) {
set.addAll(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project));
}
@NotNull
@Override
public PsiField[] getFieldsByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) {
return NO_FIELDS;
}
@NotNull
@Override
public String[] getAllFieldNames() {
return ArrayUtil.EMPTY_STRING_ARRAY;
}
@Override
public void getAllFieldNames(@NotNull HashSet<String> set) {
}
}
@@ -0,0 +1,214 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.caches.resolve;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.libraries.LibraryUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.KotlinLightClassForExplicitDeclaration;
import org.jetbrains.jet.asJava.LightClassConstructionContext;
import org.jetbrains.jet.asJava.LightClassGenerationSupport;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.plugin.libraries.JetSourceNavigationHelper;
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
import org.jetbrains.jet.plugin.stubindex.JetAllPackagesIndex;
import org.jetbrains.jet.plugin.stubindex.JetClassByPackageIndex;
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.PackageIndexUtil;
import java.util.*;
import static org.jetbrains.jet.plugin.stubindex.JetSourceFilterScope.kotlinSources;
public class IDELightClassGenerationSupport extends LightClassGenerationSupport {
private static final Logger LOG = Logger.getInstance(IDELightClassGenerationSupport.class);
public static IDELightClassGenerationSupport getInstanceForIDE(@NotNull Project project) {
return (IDELightClassGenerationSupport) ServiceManager.getService(project, LightClassGenerationSupport.class);
}
private final Project project;
private final Comparator<JetFile> jetFileComparator;
public IDELightClassGenerationSupport(@NotNull Project project) {
this.project = project;
final GlobalSearchScope searchScope = GlobalSearchScope.allScope(project);
this.jetFileComparator = new Comparator<JetFile>() {
@Override
public int compare(@NotNull JetFile o1, @NotNull JetFile o2) {
VirtualFile f1 = o1.getVirtualFile();
VirtualFile f2 = o2.getVirtualFile();
if (f1 == f2) return 0;
if (f1 == null) return -1;
if (f2 == null) return 1;
return searchScope.compare(f1, f2);
}
};
}
@NotNull
@Override
public LightClassConstructionContext getContextForPackage(@NotNull Collection<JetFile> files) {
assert !files.isEmpty() : "No files in package";
List<JetFile> sortedFiles = new ArrayList<JetFile>(files);
Collections.sort(sortedFiles, jetFileComparator);
ResolveSessionForBodies session = ResolvePackage.getLazyResolveSession(sortedFiles.get(0));
forceResolvePackageDeclarations(files, session);
return new LightClassConstructionContext(session.getBindingContext(), session.getModuleDescriptor());
}
@NotNull
@Override
public LightClassConstructionContext getContextForClassOrObject(@NotNull JetClassOrObject classOrObject) {
ResolveSessionForBodies session = ResolvePackage.getLazyResolveSession(classOrObject);
if (classOrObject.isLocal()) {
BindingContext bindingContext = session.resolveToElement(classOrObject);
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
if (descriptor == null) {
LOG.warn("No class descriptor in context for class: " + JetPsiUtil.getElementTextWithContext(classOrObject));
return new LightClassConstructionContext(BindingContext.EMPTY, session.getModuleDescriptor());
}
ForceResolveUtil.forceResolveAllContents(descriptor);
return new LightClassConstructionContext(bindingContext, session.getModuleDescriptor());
}
ForceResolveUtil.forceResolveAllContents(session.getClassDescriptor(classOrObject));
return new LightClassConstructionContext(session.getBindingContext(), session.getModuleDescriptor());
}
private static void forceResolvePackageDeclarations(@NotNull Collection<JetFile> files, @NotNull KotlinCodeAnalyzer session) {
for (JetFile file : files) {
// SCRIPT: not supported
if (file.isScript()) continue;
FqName packageFqName = file.getPackageFqName();
// make sure we create a package descriptor
PackageViewDescriptor packageDescriptor = session.getModuleDescriptor().getPackage(packageFqName);
if (packageDescriptor == null) {
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.getName() + "\n" + file.getText());
session.forceResolveAll();
continue;
}
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetFunction) {
JetFunction jetFunction = (JetFunction) declaration;
Name name = jetFunction.getNameAsSafeName();
Collection<FunctionDescriptor> functions = packageDescriptor.getMemberScope().getFunctions(name);
for (FunctionDescriptor descriptor : functions) {
ForceResolveUtil.forceResolveAllContents(descriptor);
}
}
else if (declaration instanceof JetProperty) {
JetProperty jetProperty = (JetProperty) declaration;
Name name = jetProperty.getNameAsSafeName();
Collection<VariableDescriptor> properties = packageDescriptor.getMemberScope().getProperties(name);
for (VariableDescriptor descriptor : properties) {
ForceResolveUtil.forceResolveAllContents(descriptor);
}
}
else if (declaration instanceof JetClassOrObject) {
// Do nothing: we are not interested in classes
}
else {
LOG.error("Unsupported declaration kind: " + declaration + " in file " + file.getName() + "\n" + file.getText());
}
}
}
}
@NotNull
@Override
public Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope) {
return JetFullClassNameIndex.getInstance().get(fqName.asString(), project, kotlinSources(searchScope, project));
}
@NotNull
@Override
public Collection<JetFile> findFilesForPackage(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope) {
return PackageIndexUtil.findFilesWithExactPackage(fqName, kotlinSources(searchScope, project), project);
}
@NotNull
@Override
public Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
@NotNull FqName packageFqName, @NotNull GlobalSearchScope searchScope
) {
return JetClassByPackageIndex.getInstance().get(packageFqName.asString(), project, kotlinSources(searchScope, project));
}
@Override
public boolean packageExists(@NotNull FqName fqName, @NotNull GlobalSearchScope scope) {
return !JetAllPackagesIndex.getInstance().get(fqName.asString(), project, kotlinSources(scope, project)).isEmpty();
}
@NotNull
@Override
public Collection<FqName> getSubPackages(@NotNull FqName fqn, @NotNull GlobalSearchScope scope) {
return PackageIndexUtil.getSubPackageFqNames(fqn, kotlinSources(scope, project), project);
}
@Nullable
@Override
public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) {
VirtualFile virtualFile = classOrObject.getContainingFile().getVirtualFile();
if (virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, classOrObject.getProject()) != null) {
return JetSourceNavigationHelper.getOriginalClass(classOrObject);
}
return KotlinLightClassForExplicitDeclaration.create(classOrObject.getManager(), classOrObject);
}
@NotNull
public MultiMap<String, FqName> getAllPossiblePackageClasses(@NotNull GlobalSearchScope scope) {
Collection<String> packageFqNames = JetAllPackagesIndex.getInstance().getAllKeys(project);
MultiMap<String, FqName> result = new MultiMap<String, FqName>();
for (String packageFqName : packageFqNames) {
FqName packageClassFqName = PackageClassUtils.getPackageClassFqName(new FqName(packageFqName));
result.putValue(packageClassFqName.shortName().asString(), packageClassFqName);
}
return result;
}
}
@@ -0,0 +1,145 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.caches.resolve
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.lang.psi.JetFile
import com.intellij.openapi.project.Project
import org.jetbrains.jet.analyzer.AnalyzeExhaust
import com.intellij.openapi.diagnostic.Logger
import com.intellij.util.containers.SLRUCache
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.psi.util.CachedValueProvider
import org.jetbrains.jet.lang.resolve.BindingContext
import com.intellij.openapi.components.ServiceManager
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.jet.plugin.project.AnalyzerFacadeProvider
import org.jetbrains.jet.plugin.project.TargetPlatform
import org.jetbrains.jet.plugin.project.TargetPlatform.*
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import org.jetbrains.jet.plugin.project.TargetPlatformDetector
import org.jetbrains.jet.lang.psi.JetCodeFragment
import org.jetbrains.jet.plugin.stubindex.JetSourceFilterScope
private val LOG = Logger.getInstance(javaClass<KotlinCacheService>())
fun JetElement.getLazyResolveSession(): ResolveSessionForBodies {
return KotlinCacheService.getInstance(getProject()).getLazyResolveSession(this)
}
fun Project.getLazyResolveSession(platform: TargetPlatform): ResolveSessionForBodies {
return KotlinCacheService.getInstance(this).getGlobalLazyResolveSession(platform)
}
fun JetElement.getAnalysisResults(): AnalyzeExhaust {
return KotlinCacheService.getInstance(getProject()).getAnalysisResults(listOf(this))
}
fun JetElement.getBindingContext(): BindingContext {
return getAnalysisResults().getBindingContext()
}
fun getAnalysisResultsForElements(elements: Collection<JetElement>): AnalyzeExhaust {
if (elements.isEmpty()) return AnalyzeExhaust.EMPTY
val element = elements.first()
return KotlinCacheService.getInstance(element.getProject()).getAnalysisResults(elements)
}
class KotlinCacheService(val project: Project) {
class object {
fun getInstance(project: Project) = ServiceManager.getService(project, javaClass<KotlinCacheService>())!!
}
private fun globalResolveSessionProvider(platform: TargetPlatform, syntheticFiles: Collection<JetFile> = listOf()) = {
val setup = AnalyzerFacadeProvider.getAnalyzerFacade(platform)
.createSetup(project, syntheticFiles, GlobalSearchScope.allScope(project))
val resolveSessionForBodies = ResolveSessionForBodies(project, setup.getLazyResolveSession())
CachedValueProvider.Result.create(
SessionAndSetup(
platform,
resolveSessionForBodies,
setup
),
PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT,
resolveSessionForBodies
)
}
private val globalCachesPerPlatform = mapOf(
JVM to KotlinResolveCache(project, globalResolveSessionProvider(JVM)),
JS to KotlinResolveCache(project, globalResolveSessionProvider(JS))
)
private val syntheticFileCaches = object : SLRUCache<JetFile, KotlinResolveCache>(2, 3) {
override fun createValue(file: JetFile?): KotlinResolveCache {
return KotlinResolveCache(
project,
globalResolveSessionProvider(
TargetPlatformDetector.getPlatform(file!!),
listOf(file)
)
)
}
}
private fun getCacheForSyntheticFile(file: JetFile): KotlinResolveCache {
return synchronized(syntheticFileCaches) {
syntheticFileCaches[file]
}
}
public fun getGlobalLazyResolveSession(platform: TargetPlatform): ResolveSessionForBodies {
return globalCachesPerPlatform[platform]!!.getLazyResolveSession()
}
public fun getLazyResolveSession(element: JetElement): ResolveSessionForBodies {
val file = element.getContainingJetFile()
if (!isFileInScope(file)) {
return getCacheForSyntheticFile(file).getLazyResolveSession()
}
return getGlobalLazyResolveSession(TargetPlatformDetector.getPlatform(file))
}
public fun getAnalysisResults(elements: Collection<JetElement>): AnalyzeExhaust {
if (elements.isEmpty()) return AnalyzeExhaust.EMPTY
val firstFile = elements.first().getContainingJetFile()
if (elements.size == 1 && (!isFileInScope(firstFile) && firstFile !is JetCodeFragment)) {
return getCacheForSyntheticFile(firstFile).getAnalysisResultsForElements(elements)
}
val resolveCache = globalCachesPerPlatform[TargetPlatformDetector.getPlatform(firstFile)]!!
return resolveCache.getAnalysisResultsForElements(elements)
}
private fun isFileInScope(jetFile: JetFile): Boolean {
val virtualFile = jetFile.getVirtualFile()
if (virtualFile == null) {
return false
}
return virtualFile in kotlinSourcesInProjectScope()
}
private fun kotlinSourcesInProjectScope(): GlobalSearchScope {
return JetSourceFilterScope.kotlinSources(GlobalSearchScope.allScope(project), project)
}
public fun <T> get(extension: CacheExtension<T>): T {
return globalCachesPerPlatform[extension.platform]!![extension]
}
}
@@ -0,0 +1,308 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.caches.resolve
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.lang.psi.JetFile
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.openapi.project.Project
import org.jetbrains.jet.analyzer.AnalyzeExhaust
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils
import com.intellij.util.containers.SLRUCache
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.openapi.project.DumbService
import org.jetbrains.jet.plugin.util.ApplicationUtils
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace
import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm
import org.jetbrains.jet.context.SimpleGlobalContext
import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.psi.util.CachedValueProvider
import org.jetbrains.jet.asJava.LightClassUtil
import com.intellij.openapi.roots.libraries.LibraryUtil
import org.jetbrains.jet.lang.resolve.LibrarySourceHacks
import org.jetbrains.jet.plugin.project.TargetPlatform
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import org.jetbrains.jet.analyzer.AnalyzerFacade
import java.util.HashMap
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.psi.JetNamedFunction
import org.jetbrains.jet.lang.psi.JetClassInitializer
import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.jet.lang.psi.JetImportDirective
import org.jetbrains.jet.lang.psi.JetAnnotationEntry
import org.jetbrains.jet.lang.psi.JetTypeConstraint
import org.jetbrains.jet.lang.psi.JetPackageDirective
import org.jetbrains.jet.lang.psi.JetPsiUtil
import org.jetbrains.jet.lang.psi.JetDeclaration
import org.jetbrains.jet.lang.resolve.CompositeBindingContext
import org.jetbrains.jet.lang.psi.JetParameter
import org.jetbrains.jet.lang.psi.JetDelegationSpecifierList
import org.jetbrains.jet.lang.psi.JetTypeParameter
import org.jetbrains.jet.lang.psi.JetClassOrObject
import org.jetbrains.jet.lang.psi.JetCallableDeclaration
import org.jetbrains.jet.lang.psi.JetCodeFragment
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo
import org.jetbrains.jet.analyzer.analyzeInContext
import org.jetbrains.jet.lang.resolve.BindingTraceContext
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.resolve.scopes.ChainedScope
public trait CacheExtension<T> {
val platform: TargetPlatform
fun getData(setup: AnalyzerFacade.Setup): T
}
private class SessionAndSetup(
val platform: TargetPlatform,
val resolveSessionForBodies: ResolveSessionForBodies,
val setup: AnalyzerFacade.Setup
)
private class KotlinResolveCache(
val project: Project,
setupProvider: () -> CachedValueProvider.Result<SessionAndSetup>
) {
private val setupCache = SynchronizedCachedValue(project, setupProvider, trackValue = false)
public fun getLazyResolveSession(): ResolveSessionForBodies = setupCache.getValue().resolveSessionForBodies
public fun <T> get(extension: CacheExtension<T>): T {
val sessionAndSetup = setupCache.getValue()
assert(extension.platform == sessionAndSetup.platform,
"Extension $extension declares platfrom ${extension.platform} which is incompatible with ${sessionAndSetup.platform}")
return extension.getData(sessionAndSetup.setup)
}
private val analysisResults = CachedValuesManager.getManager(project).createCachedValue ({
val resolveSession = getLazyResolveSession()
val results = object : SLRUCache<JetFile, PerFileAnalysisCache>(2, 3) {
override fun createValue(file: JetFile?): PerFileAnalysisCache {
return PerFileAnalysisCache(file!!, resolveSession)
}
}
CachedValueProvider.Result(results, PsiModificationTracker.MODIFICATION_COUNT, resolveSession.getExceptionTracker())
}, false)
fun getAnalysisResultsForElements(elements: Collection<JetElement>): AnalyzeExhaust {
val slruCache = synchronized(analysisResults) {
analysisResults.getValue()!!
}
val results = elements.map {
val perFileCache = synchronized(slruCache) {
slruCache[it.getContainingJetFile()]
}
perFileCache.getAnalysisResults(it)
}
val error = results.firstOrNull { it.isError() }
val bindingContext = CompositeBindingContext.create(results.map { it.getBindingContext() })
return if (error != null)
AnalyzeExhaust.error(bindingContext, error.getError())
else
AnalyzeExhaust.success(bindingContext, getLazyResolveSession().getModuleDescriptor())
}
}
private class PerFileAnalysisCache(val file: JetFile, val resolveSession: ResolveSessionForBodies) {
private val cache = HashMap<PsiElement, AnalyzeExhaust>()
private fun lookUp(analyzableElement: JetElement): AnalyzeExhaust? {
// Looking for parent elements that are already analyzed
// Also removing all elements whose parents are already analyzed, to guarantee consistency
val descendantsOfCurrent = arrayListOf<PsiElement>()
val toRemove = hashSetOf<PsiElement>()
var current: PsiElement? = analyzableElement
var result: AnalyzeExhaust? = null
while (current != null) {
val cached = cache[current]
if (cached != null) {
result = cached
toRemove.addAll(descendantsOfCurrent)
descendantsOfCurrent.clear()
}
descendantsOfCurrent.add(current!!)
current = current!!.getParent()
}
cache.keySet().removeAll(toRemove)
return result
}
fun getAnalysisResults(element: JetElement): AnalyzeExhaust {
assert (element.getContainingJetFile() == file, "Wrong file. Expected $file, but was ${element.getContainingJetFile()}")
val analyzableParent = KotlinResolveDataProvider.findAnalyzableParent(element)
return synchronized(this) { (): AnalyzeExhaust ->
val cached = lookUp(analyzableParent)
if (cached != null) return@synchronized cached
val result = analyze(analyzableParent)
cache[analyzableParent] = result
return@synchronized result
}
}
private fun analyze(analyzableElement: JetElement): AnalyzeExhaust {
val project = analyzableElement.getProject()
if (DumbService.isDumb(project)) {
return AnalyzeExhaust.EMPTY
}
ApplicationUtils.warnTimeConsuming(LOG)
try {
return KotlinResolveDataProvider.analyze(project, resolveSession, analyzableElement)
}
catch (e: ProcessCanceledException) {
throw e
}
catch (e: Throwable) {
DiagnosticUtils.throwIfRunningOnServer(e)
LOG.error(e)
return AnalyzeExhaust.error(BindingContext.EMPTY, e)
}
}
}
private object KotlinResolveDataProvider {
private val topmostElementTypes = array<Class<out PsiElement?>?>(
javaClass<JetNamedFunction>(),
javaClass<JetClassInitializer>(),
javaClass<JetProperty>(),
javaClass<JetImportDirective>(),
javaClass<JetPackageDirective>(),
javaClass<JetCodeFragment>(),
// TODO: Non-analyzable so far, add more granular analysis
javaClass<JetAnnotationEntry>(),
javaClass<JetTypeConstraint>(),
javaClass<JetDelegationSpecifierList>(),
javaClass<JetTypeParameter>(),
javaClass<JetParameter>()
)
fun findAnalyzableParent(element: JetElement): JetElement {
val topmostElement = JetPsiUtil.getTopmostParentOfTypes(element, *topmostElementTypes) as JetElement?
// parameters and supertype lists are not analyzable by themselves, but if we don't count them as topmost, we'll stop inside, say,
// object expressions inside arguments of super constructors of classes (note that classes themselves are not topmost elements)
val analyzableElement = when (topmostElement) {
is JetAnnotationEntry,
is JetTypeConstraint,
is JetDelegationSpecifierList,
is JetTypeParameter,
is JetParameter -> PsiTreeUtil.getParentOfType(topmostElement, javaClass<JetClassOrObject>(), javaClass<JetCallableDeclaration>())
else -> topmostElement
}
return analyzableElement
// if none of the above worked, take the outermost declaration
?: PsiTreeUtil.getTopmostParentOfType(element, javaClass<JetDeclaration>())
// if even that didn't work, take the whole file
?: element.getContainingJetFile()
}
fun analyze(project: Project, resolveSession: ResolveSessionForBodies, analyzableElement: JetElement): AnalyzeExhaust {
try {
if (analyzableElement is JetCodeFragment) {
return AnalyzeExhaust.success(
analyzeExpressionCodeFragment(resolveSession, analyzableElement),
resolveSession.getModuleDescriptor()
)
}
val file = analyzableElement.getContainingJetFile()
val virtualFile = file.getVirtualFile()
if (LightClassUtil.belongsToKotlinBuiltIns(file)
|| virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, file.getProject()) != null) {
// Library sources: mark file to skip
file.putUserData(LibrarySourceHacks.SKIP_TOP_LEVEL_MEMBERS, true)
}
val trace = DelegatingBindingTrace(resolveSession.getBindingContext(), "Trace for resolution of " + analyzableElement)
val injector = InjectorForTopDownAnalyzerForJvm(
project,
SimpleGlobalContext(resolveSession.getStorageManager(), resolveSession.getExceptionTracker()),
trace,
resolveSession.getModuleDescriptor()
)
injector.getLazyTopDownAnalyzer()!!.analyzeDeclarations(
resolveSession,
TopDownAnalysisParameters.createForLazy(
resolveSession.getStorageManager(),
resolveSession.getExceptionTracker(),
/* analyzeCompletely = */ { true },
/* analyzingBootstrapLibrary = */ false,
/* declaredLocally = */ false
),
listOf(analyzableElement)
)
return AnalyzeExhaust.success(
trace.getBindingContext(),
resolveSession.getModuleDescriptor()
)
}
catch (e: ProcessCanceledException) {
throw e
}
catch (e: Throwable) {
DiagnosticUtils.throwIfRunningOnServer(e)
LOG.error(e)
return AnalyzeExhaust.error(BindingContext.EMPTY, e)
}
}
private fun analyzeExpressionCodeFragment(resolveSession: ResolveSessionForBodies, codeFragment: JetCodeFragment): BindingContext {
val codeFragmentExpression = codeFragment.getContentElement()
if (codeFragmentExpression !is JetExpression) return BindingContext.EMPTY
val contextElement = codeFragment.getContext()
if (contextElement !is JetExpression) return BindingContext.EMPTY
val contextForElement = contextElement.getBindingContext()
val scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, contextElement]
if (scopeForContextElement == null) return BindingContext.EMPTY
val codeFragmentScope = resolveSession.getScopeProvider().getFileScope(codeFragment)
val chainedScope = ChainedScope(
scopeForContextElement.getContainingDeclaration(),
"Scope for resolve code fragment",
scopeForContextElement, codeFragmentScope)
val dataFlowInfoForContextElement = contextForElement[BindingContext.EXPRESSION_DATA_FLOW_INFO, contextElement]
val dataFlowInfo = dataFlowInfoForContextElement ?: DataFlowInfo.EMPTY
return codeFragmentExpression.analyzeInContext(
chainedScope,
BindingTraceContext(),
dataFlowInfo,
TypeUtils.NO_EXPECTED_TYPE,
resolveSession.getModuleDescriptor()
)
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.CachedValueProvider
class SynchronizedCachedValue<V>(project: Project, provider: () -> CachedValueProvider.Result<V>, trackValue: Boolean = true) {
private val cachedValue = CachedValuesManager.getManager(project).createCachedValue(
provider,
trackValue
)
public fun getValue(): V {
return synchronized(cachedValue) {
cachedValue.getValue() as V
}
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.codeInsight;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
import org.jetbrains.jet.plugin.libraries.DecompiledNavigationUtils;
import org.jetbrains.jet.plugin.references.BuiltInsReferenceResolver;
import java.util.Collection;
import java.util.Collections;
public final class DescriptorToDeclarationUtil {
private DescriptorToDeclarationUtil() {
}
@Nullable
public static PsiElement getDeclaration(@NotNull JetFile file, @NotNull DeclarationDescriptor descriptor) {
return getDeclaration(file.getProject(), descriptor);
}
@Nullable
public static PsiElement getDeclaration(@NotNull Project project, @NotNull DeclarationDescriptor descriptor) {
Collection<PsiElement> elements = DescriptorToSourceUtils.descriptorToDeclarations(descriptor);
if (elements.isEmpty()) {
elements = findDecompiledAndBuiltInDeclarations(project, descriptor);
}
if (!elements.isEmpty()) {
return elements.iterator().next();
}
return null;
}
@NotNull
public static Collection<PsiElement> findDecompiledAndBuiltInDeclarations(
@NotNull Project project,
@NotNull DeclarationDescriptor descriptor
) {
BuiltInsReferenceResolver libraryReferenceResolver = project.getComponent(BuiltInsReferenceResolver.class);
Collection<PsiElement> elements = libraryReferenceResolver.resolveBuiltInSymbol(descriptor);
if (!elements.isEmpty()) {
return elements;
}
JetDeclaration decompiledDeclaration = DecompiledNavigationUtils.findDeclarationForReference(project, descriptor);
if (decompiledDeclaration != null) {
return Collections.<PsiElement>singleton(decompiledDeclaration);
}
return Collections.emptySet();
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.configuration;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
public abstract class JetModuleTypeManager {
public static JetModuleTypeManager getInstance() {
return ServiceManager.getService(JetModuleTypeManager.class);
}
public abstract boolean isKtFileInGradleProjectInWrongFolder(@NotNull PsiElement element);
public abstract boolean isKtFileInGradleProjectInWrongFolder(@NotNull VirtualFile virtualFile, @NotNull Project project);
public abstract boolean isAndroidGradleModule(@NotNull Module module);
public boolean isGradleModule(@NotNull Module module) {
return ModuleTypeCacheManager.OBJECT$.geInstance(module.getProject()).isGradleModule(module);
}
}
@@ -0,0 +1,104 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.configuration
import com.intellij.openapi.module.Module
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter
import com.intellij.openapi.vfs.VirtualFileAdapter
import com.intellij.openapi.vfs.VirtualFileEvent
import com.intellij.openapi.vfs.VirtualFileMoveEvent
import com.intellij.openapi.vfs.VirtualFileCopyEvent
import com.intellij.openapi.vfs.VirtualFilePropertyEvent
import com.intellij.openapi.util.SimpleModificationTracker
class ModuleTypeCacheManager private (project: Project) {
class object {
fun geInstance(project: Project) = ServiceManager.getService(project, javaClass<ModuleTypeCacheManager>())
}
private val vfsModificationTracker = VfsModificationTracker(project)
private val cachedValue = CachedValuesManager.getManager(project).createParameterizedCachedValue(
{
(module: Module?) ->
val moduleType = if (module != null) computeType(module) else null
CachedValueProvider.Result.create<ModuleType>(moduleType, vfsModificationTracker)
}, false)
fun isGradleModule(module: Module) = getModuleType(module) == ModuleType.GRADLE
private fun getModuleType(module: Module): ModuleType? {
return cachedValue?.getValue(module)
}
private class VfsModificationTracker(project: Project): SimpleModificationTracker() {
{
val connection = project.getMessageBus().connect();
connection.subscribe(VirtualFileManager.VFS_CHANGES, BulkVirtualFileListenerAdapter(
object : VirtualFileAdapter() {
override fun propertyChanged(event: VirtualFilePropertyEvent) {
incModificationCount()
}
override fun fileCreated(event: VirtualFileEvent) {
incModificationCount()
}
override fun fileDeleted(event: VirtualFileEvent) {
incModificationCount()
}
override fun fileMoved(event: VirtualFileMoveEvent) {
incModificationCount()
}
override fun fileCopied(event: VirtualFileCopyEvent) {
incModificationCount()
}
}
))
}
}
}
enum class ModuleType {
GRADLE
OTHER
}
private fun computeType(module: Module) =
when {
isGradleModule(module) -> ModuleType.GRADLE
else -> ModuleType.OTHER
}
private val DEFAULT_SCRIPT_NAME = "build.gradle"
private fun isGradleModule(module: Module): Boolean {
val moduleFile = module.getModuleFile()
if (moduleFile == null){
return false
}
val buildFile = moduleFile.getParent()?.findChild(DEFAULT_SCRIPT_NAME)
return buildFile != null && buildFile.exists()
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.framework;
import com.intellij.openapi.util.io.JarUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.utils.PathUtil;
import java.util.List;
import java.util.jar.Attributes;
public class JavaRuntimeDetectionUtil {
public static String getJavaRuntimeVersion(@NotNull List<VirtualFile> classesRoots) {
VirtualFile stdJar = getRuntimeJar(classesRoots);
if (stdJar != null) {
return JarUtil.getJarAttribute(VfsUtilCore.virtualToIoFile(stdJar), Attributes.Name.IMPLEMENTATION_VERSION);
}
return null;
}
@Nullable
public static VirtualFile getRuntimeJar(@NotNull List<VirtualFile> classesRoots) {
return getJarFile(classesRoots, PathUtil.KOTLIN_JAVA_RUNTIME_JAR);
}
static VirtualFile getJarFile(@NotNull List<VirtualFile> classesRoots, @NotNull String jarName) {
for (VirtualFile root : classesRoots) {
if (root.getName().equals(jarName)) {
return root;
}
}
return null;
}
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.framework;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.CommonProcessors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.plugin.JetFileType;
import java.util.List;
public class JsHeaderLibraryDetectionUtil {
public static boolean isJsHeaderLibraryDetected(@NotNull List<VirtualFile> classesRoots) {
if (JavaRuntimeDetectionUtil.getJavaRuntimeVersion(classesRoots) != null) {
// Prevent clashing with java runtime
return false;
}
for (VirtualFile file : classesRoots) {
CommonProcessors.FindFirstProcessor<VirtualFile> findKTProcessor = new CommonProcessors.FindFirstProcessor<VirtualFile>() {
@Override
protected boolean accept(VirtualFile file) {
String extension = file.getExtension();
return extension != null && extension.equals(JetFileType.INSTANCE.getDefaultExtension());
}
};
VfsUtilCore.processFilesRecursively(file, findKTProcessor);
if (findKTProcessor.isFound()) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.framework;
import com.intellij.openapi.util.io.JarUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.utils.PathUtil;
import java.util.List;
import java.util.jar.Attributes;
public class JsLibraryStdDetectionUtil {
public static String getJsLibraryStdVersion(@NotNull List<VirtualFile> classesRoots) {
if (JavaRuntimeDetectionUtil.getJavaRuntimeVersion(classesRoots) != null) {
// Prevent clashing with java runtime, in case when library collects all roots.
return null;
}
for (VirtualFile root : classesRoots) {
if (root.getName().equals(PathUtil.JS_LIB_JAR_NAME)) {
assert JsHeaderLibraryDetectionUtil.isJsHeaderLibraryDetected(classesRoots) : "StdLib should also be detected as headers library";
return JarUtil.getJarAttribute(VfsUtilCore.virtualToIoFile(root), Attributes.Name.IMPLEMENTATION_VERSION);
}
}
return null;
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import org.jetbrains.jet.lang.resolve.BindingContext;
abstract class AfterAnalysisHighlightingVisitor extends HighlightingVisitor {
protected BindingContext bindingContext;
protected AfterAnalysisHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext) {
super(holder);
this.bindingContext = bindingContext;
}
}
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.checkers.DebugInfoUtil;
import org.jetbrains.jet.lang.psi.JetCodeFragment;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.plugin.ProjectRootsUtil;
import org.jetbrains.jet.plugin.actions.internal.KotlinInternalMode;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.configuration.JetModuleTypeManager;
/**
* Quick showing possible problems with Kotlin internals in IDEA with tooltips
*/
public class DebugInfoAnnotator implements Annotator {
public static boolean isDebugInfoEnabled() {
return KotlinInternalMode.OBJECT$.getEnabled();
}
@Override
public void annotate(@NotNull PsiElement element, @NotNull final AnnotationHolder holder) {
if (!isDebugInfoEnabled() ||
!ProjectRootsUtil.isInSource(element) ||
JetModuleTypeManager.getInstance().isKtFileInGradleProjectInWrongFolder(element)) {
return;
}
if (element instanceof JetFile && !(element instanceof JetCodeFragment)) {
JetFile file = (JetFile) element;
try {
BindingContext bindingContext = ResolvePackage.getBindingContext(file);
DebugInfoUtil.markDebugAnnotations(file, bindingContext, new DebugInfoUtil.DebugInfoReporter() {
@Override
public void reportElementWithErrorType(@NotNull JetReferenceExpression expression) {
holder.createErrorAnnotation(expression, "[DEBUG] Resolved to error element")
.setTextAttributes(JetHighlightingColors.RESOLVED_TO_ERROR);
}
@Override
public void reportMissingUnresolved(@NotNull JetReferenceExpression expression) {
holder.createErrorAnnotation(expression,
"[DEBUG] Reference is not resolved to anything, but is not marked unresolved")
.setTextAttributes(JetHighlightingColors.DEBUG_INFO);
}
@Override
public void reportUnresolvedWithTarget(@NotNull JetReferenceExpression expression, @NotNull String target) {
holder.createErrorAnnotation(expression, "[DEBUG] Reference marked as unresolved is actually resolved to " + target)
.setTextAttributes(JetHighlightingColors.DEBUG_INFO);
}
});
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
// TODO
holder.createErrorAnnotation(element, e.getClass().getCanonicalName() + ": " + e.getMessage());
e.printStackTrace();
}
}
}
}
@@ -0,0 +1,283 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME;
public class DeprecatedAnnotationVisitor extends AfterAnalysisHighlightingVisitor {
private static final TokenSet PROPERTY_SET_OPERATIONS =
TokenSet.create(JetTokens.EQ, JetTokens.PLUSEQ, JetTokens.MINUSEQ, JetTokens.MULTEQ,
JetTokens.DIVEQ, JetTokens.PERCEQ, JetTokens.PLUSPLUS, JetTokens.MINUSMINUS);
private static final FqName JAVA_DEPRECATED = new FqName(Deprecated.class.getName());
private static final FqName KOTLIN_DEPRECATED = DescriptorUtils.getFqNameSafe(KotlinBuiltIns.getInstance().getDeprecatedAnnotation());
protected DeprecatedAnnotationVisitor(AnnotationHolder holder, BindingContext bindingContext) {
super(holder, bindingContext);
}
@Override
public void visitSuperExpression(@NotNull JetSuperExpression expression) {
// Deprecated for super expression. Unnecessary to mark it as Deprecated
}
@Override
public void visitReferenceExpression(@NotNull JetReferenceExpression expression) {
super.visitReferenceExpression(expression);
ResolvedCall resolvedCall = CallUtilPackage.getResolvedCall(expression, bindingContext);
if (resolvedCall != null && resolvedCall instanceof VariableAsFunctionResolvedCall) {
// Deprecated for invoke()
JetCallExpression parent = PsiTreeUtil.getParentOfType(expression, JetCallExpression.class);
if (parent != null) {
reportAnnotationIfNeeded(parent, resolvedCall.getResultingDescriptor(), true);
}
}
if (expression.getNode().getElementType() == JetNodeTypes.OPERATION_REFERENCE) {
// Deprecated for operations (mark as warning)
checkDeprecatedForOperations(expression);
}
else {
checkDeprecatedForReferenceExpression(expression);
}
}
private void checkDeprecatedForReferenceExpression(@NotNull JetReferenceExpression expression) {
DeclarationDescriptor target = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
if (target != null) {
if (target instanceof ConstructorDescriptor) {
checkConstructorDescriptor(expression, target);
}
else if (target instanceof ClassDescriptor) {
checkClassDescriptor(expression, (ClassDescriptor) target);
}
else if (target instanceof PropertyDescriptor) {
checkPropertyDescriptor(expression, (PropertyDescriptor) target);
}
else if (target instanceof FunctionDescriptor) {
checkFunctionDescriptor(expression, target);
}
}
}
private void checkFunctionDescriptor(JetExpression expression, DeclarationDescriptor target) {
// Deprecated for Function
reportAnnotationIfNeeded(expression, target, expression instanceof JetArrayAccessExpression);
}
private void checkConstructorDescriptor(@NotNull JetExpression expression, @NotNull DeclarationDescriptor target) {
// Deprecated for Class and for Constructor
DeclarationDescriptor containingDeclaration = target.getContainingDeclaration();
if (containingDeclaration != null) {
if (!reportAnnotationIfNeeded(expression, containingDeclaration)) {
reportAnnotationIfNeeded(expression, target);
}
}
}
private void checkClassDescriptor(@NotNull JetExpression expression, @NotNull ClassDescriptor target) {
// Deprecated for Class, for ClassObject (if reference isn't in UserType or in ModifierList (trait))
if (!reportAnnotationIfNeeded(expression, target)) {
if (PsiTreeUtil.getParentOfType(expression, JetUserType.class) == null &&
PsiTreeUtil.getParentOfType(expression, JetModifierList.class) == null) {
ClassDescriptor classObjectDescriptor = target.getClassObjectDescriptor();
if (classObjectDescriptor != null) {
reportAnnotationIfNeeded(expression, classObjectDescriptor);
}
}
}
}
private void checkPropertyDescriptor(
@NotNull JetExpression expression,
@NotNull PropertyDescriptor propertyDescriptor
) {
// Deprecated for Property
if (reportAnnotationIfNeeded(expression, propertyDescriptor, propertyDescriptor.isVar())) {
return;
}
// Deprecated for Getter (val, var), Setter (var)
if (!propertyDescriptor.isVar()) {
checkPropertyGetter(propertyDescriptor, expression);
}
else {
IElementType operation = null;
JetBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(expression, JetBinaryExpression.class);
if (binaryExpression != null) {
JetExpression left = binaryExpression.getLeft();
if (left == expression) {
operation = binaryExpression.getOperationToken();
}
else {
JetReferenceExpression[] jetReferenceExpressions = PsiTreeUtil.getChildrenOfType(left, JetReferenceExpression.class);
if (jetReferenceExpressions != null) {
for (JetReferenceExpression expr : jetReferenceExpressions) {
if (expr == expression) {
operation = binaryExpression.getOperationToken();
break;
}
}
}
}
}
else {
JetUnaryExpression unaryExpression = PsiTreeUtil.getParentOfType(expression, JetUnaryExpression.class);
if (unaryExpression != null) {
operation = unaryExpression.getOperationReference().getReferencedNameElementType();
}
}
if (operation != null && PROPERTY_SET_OPERATIONS.contains(operation)) {
checkPropertySetter(propertyDescriptor, expression);
}
else {
checkPropertyGetter(propertyDescriptor, expression);
}
}
}
private void checkPropertySetter(@NotNull PropertyDescriptor descriptor, @NotNull JetExpression expression) {
PropertySetterDescriptor setter = descriptor.getSetter();
if (setter != null) {
checkPropertyAccessor(setter, expression, true);
}
}
private void checkPropertyGetter(@NotNull PropertyDescriptor descriptor, @NotNull JetExpression expression) {
PropertyGetterDescriptor getter = descriptor.getGetter();
if (getter != null) {
checkPropertyAccessor(getter, expression, descriptor.isVar());
}
}
private void checkPropertyAccessor(
@NotNull PropertyAccessorDescriptor accessor,
@NotNull JetExpression expression, boolean isCrossingDisallowed
) {
reportAnnotationIfNeeded(expression, accessor, isCrossingDisallowed);
}
private void checkDeprecatedForOperations(@NotNull JetReferenceExpression expression) {
DeclarationDescriptor target = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
if (target != null) {
reportAnnotationIfNeeded(expression, target, true);
}
}
private boolean reportAnnotationIfNeeded(@NotNull PsiElement element, @NotNull DeclarationDescriptor descriptor) {
return reportAnnotationIfNeeded(element, descriptor, false);
}
private boolean reportAnnotationIfNeeded(@NotNull PsiElement element, @NotNull DeclarationDescriptor descriptor, boolean isCrossingDisallowed) {
AnnotationDescriptor deprecated = getDeprecated(descriptor);
if (deprecated != null) {
if (isCrossingDisallowed) {
holder.createWarningAnnotation(element, composeTooltipString(descriptor, deprecated))
.setTextAttributes(CodeInsightColors.WARNINGS_ATTRIBUTES);
}
else {
holder.createWarningAnnotation(element, composeTooltipString(descriptor, deprecated))
.setTextAttributes(CodeInsightColors.DEPRECATED_ATTRIBUTES);
}
return true;
}
return false;
}
@Nullable
private static AnnotationDescriptor getDeprecated(DeclarationDescriptor descriptor) {
AnnotationDescriptor kotlinDeprecated = descriptor.getAnnotations().findAnnotation(KOTLIN_DEPRECATED);
return kotlinDeprecated != null ? kotlinDeprecated : descriptor.getAnnotations().findAnnotation(JAVA_DEPRECATED);
}
private static String composeTooltipString(@NotNull DeclarationDescriptor declarationDescriptor, @NotNull AnnotationDescriptor descriptor) {
String fact = "'" + getDescriptorString(declarationDescriptor) + "' is deprecated.";
String message = getMessageFromAnnotationDescriptor(descriptor);
return message == null ? fact : fact + " " + message;
}
@Nullable
private static String getMessageFromAnnotationDescriptor(@NotNull AnnotationDescriptor descriptor) {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(descriptor.getType());
if (classDescriptor != null) {
ValueParameterDescriptor parameter =
DescriptorResolverUtils.getAnnotationParameterByName(DEFAULT_ANNOTATION_MEMBER_NAME, classDescriptor);
if (parameter != null) {
CompileTimeConstant<?> valueArgument = descriptor.getValueArgument(parameter);
if (valueArgument != null) {
Object value = valueArgument.getValue();
if (value instanceof String) {
return String.valueOf(value);
}
}
}
}
return null;
}
private static String getDescriptorString(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ClassDescriptor) {
return DescriptorUtils.getFqName(descriptor).asString();
}
else if (descriptor instanceof ConstructorDescriptor) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
assert containingDeclaration != null;
return "constructor for " + containingDeclaration.getName();
}
else if (descriptor instanceof PropertyGetterDescriptor) {
return "getter for " + ((PropertyGetterDescriptor) descriptor).getCorrespondingProperty().getName();
}
else if (descriptor instanceof PropertySetterDescriptor) {
return "setter for " + ((PropertySetterDescriptor) descriptor).getCorrespondingProperty().getName();
}
else if (descriptor instanceof PropertyDescriptor) {
if (((PropertyDescriptor) descriptor).isVar()) {
return "var " + descriptor.getName();
}
return "val " + descriptor.getName();
}
else if (descriptor instanceof FunctionDescriptor) {
return "fun " + descriptor.getName() + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderFunctionParameters((FunctionDescriptor) descriptor);
}
return DescriptorRenderer.FQ_NAMES_IN_TYPES.render(descriptor);
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.AsJavaPackage;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.Diagnostics;
import org.jetbrains.jet.plugin.ProjectRootsUtil;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.project.TargetPlatform;
import org.jetbrains.jet.plugin.project.TargetPlatformDetector;
public class DuplicateJvmSignatureAnnotator implements Annotator {
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if (!(element instanceof JetFile) && !(element instanceof JetDeclaration)) return;
if (!ProjectRootsUtil.isInSource(element, false)) return;
PsiFile file = element.getContainingFile();
if (!(file instanceof JetFile) || TargetPlatformDetector.getPlatform((JetFile) file) != TargetPlatform.JVM) return;
Diagnostics otherDiagnostics = ResolvePackage.getBindingContext((JetElement) element).getDiagnostics();
Diagnostics diagnostics = AsJavaPackage.getJvmSignatureDiagnostics(element, otherDiagnostics);
if (diagnostics == null) return;
JetPsiChecker.annotateElement(element, holder, diagnostics);
}
}
@@ -0,0 +1,119 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
public class FunctionsHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
public FunctionsHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext) {
super(holder, bindingContext);
}
@Override
public void visitNamedFunction(@NotNull JetNamedFunction function) {
PsiElement nameIdentifier = function.getNameIdentifier();
if (nameIdentifier != null) {
JetPsiChecker.highlightName(holder, nameIdentifier, JetHighlightingColors.FUNCTION_DECLARATION);
}
super.visitNamedFunction(function);
}
@Override
public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) {
JetConstructorCalleeExpression calleeExpression = call.getCalleeExpression();
JetTypeReference typeRef = calleeExpression.getTypeReference();
if (typeRef != null) {
JetTypeElement typeElement = typeRef.getTypeElement();
if (typeElement instanceof JetUserType) {
JetSimpleNameExpression nameExpression = ((JetUserType)typeElement).getReferenceExpression();
if (nameExpression != null) {
JetPsiChecker.highlightName(holder, nameExpression, JetHighlightingColors.CONSTRUCTOR_CALL);
}
}
}
super.visitDelegationToSuperCallSpecifier(call);
}
@Override
public void visitCallExpression(@NotNull JetCallExpression expression) {
JetExpression callee = expression.getCalleeExpression();
ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, bindingContext);
if (callee instanceof JetReferenceExpression && resolvedCall != null) {
DeclarationDescriptor calleeDescriptor = resolvedCall.getResultingDescriptor();
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
JetPsiChecker.highlightName(holder, callee, containedInFunctionClassOrSubclass(calleeDescriptor)
? JetHighlightingColors.VARIABLE_AS_FUNCTION_CALL
: JetHighlightingColors.VARIABLE_AS_FUNCTION_LIKE_CALL);
}
else {
if (calleeDescriptor instanceof ConstructorDescriptor) {
JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.CONSTRUCTOR_CALL);
}
else if (calleeDescriptor instanceof FunctionDescriptor) {
FunctionDescriptor fun = (FunctionDescriptor) calleeDescriptor;
JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.FUNCTION_CALL);
if (DescriptorUtils.isTopLevelDeclaration(fun)) {
JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.PACKAGE_FUNCTION_CALL);
}
if (fun.getReceiverParameter() != null) {
JetPsiChecker.highlightName(holder, callee, JetHighlightingColors.EXTENSION_FUNCTION_CALL);
}
}
}
}
super.visitCallExpression(expression);
}
private static boolean containedInFunctionClassOrSubclass(DeclarationDescriptor calleeDescriptor) {
DeclarationDescriptor parent = calleeDescriptor.getContainingDeclaration();
if (!(parent instanceof ClassDescriptor)) {
return false;
}
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
JetType defaultType = ((ClassDescriptor) parent).getDefaultType();
if (builtIns.isFunctionOrExtensionFunctionType(defaultType)) {
return true;
}
for (JetType supertype : TypeUtils.getAllSupertypes(defaultType)) {
if (builtIns.isFunctionOrExtensionFunctionType(supertype)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import org.jetbrains.jet.lang.psi.JetVisitorVoid;
abstract class HighlightingVisitor extends JetVisitorVoid {
protected AnnotationHolder holder;
protected HighlightingVisitor(AnnotationHolder holder) {
this.holder = holder;
}
}
@@ -0,0 +1,240 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.google.common.base.Predicate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.DescriptorRow;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow;
import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.TableRow;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import org.jetbrains.jet.renderer.DescriptorRendererBuilder;
import org.jetbrains.jet.renderer.Renderer;
import java.util.Iterator;
import java.util.List;
import static org.jetbrains.jet.plugin.highlighter.IdeRenderers.error;
import static org.jetbrains.jet.plugin.highlighter.IdeRenderers.strong;
public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
@NotNull
@Override
public Renderer<JetType> getTypeRenderer() {
return IdeRenderers.HTML_RENDER_TYPE;
}
@Override
protected void renderText(TextRenderer textRenderer, StringBuilder result) {
for (TextRenderer.TextElement element : textRenderer.elements) {
renderText(result, element.type, element.text);
}
}
private static void renderText(StringBuilder result, TextElementType elementType, String text) {
if (elementType == TextElementType.DEFAULT) {
result.append(text);
}
else if (elementType == TextElementType.ERROR) {
result.append(error(text));
}
else if (elementType == TextElementType.STRONG) {
result.append(strong(text));
}
}
private static int countColumnNumber(TableRenderer table) {
int argumentsNumber = 0;
for (TableRow row : table.rows) {
if (row instanceof DescriptorRow) {
int valueParametersNumber = ((DescriptorRow) row).descriptor.getValueParameters().size();
if (valueParametersNumber > argumentsNumber) {
argumentsNumber = valueParametersNumber;
}
}
else if (row instanceof FunctionArgumentsRow) {
int argumentTypesNumber = ((FunctionArgumentsRow) row).argumentTypes.size();
if (argumentTypesNumber > argumentsNumber) {
argumentsNumber = argumentTypesNumber;
}
}
}
//magical number 6:
// <td> white-space </td> <td> receiver: ___ </td> <td> arguments: </td> <td> ( </td> arguments <td> ) </td> <td> : return_type </td>
return argumentsNumber + 6;
}
@Override
protected void renderTable(TableRenderer table, StringBuilder result) {
if (table.rows.isEmpty()) return;
int rowsNumber = countColumnNumber(table);
result.append("<table>");
for (TableRow row : table.rows) {
result.append("<tr>");
if (row instanceof TextRenderer) {
StringBuilder rowText = new StringBuilder();
renderText((TextRenderer) row, rowText);
tdColspan(result, rowText.toString(), rowsNumber);
}
if (row instanceof DescriptorRow) {
tdSpace(result);
tdRightBoldColspan(result, 2, DESCRIPTOR_IN_TABLE.render(((DescriptorRow) row).descriptor));
}
if (row instanceof FunctionArgumentsRow) {
FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, functionArgumentsRow.isErrorPosition, result);
}
result.append("</tr>");
}
result.append("</table>");
}
private void renderFunctionArguments(
@Nullable JetType receiverType,
@NotNull List<JetType> argumentTypes,
Predicate<ConstraintPosition> isErrorPosition,
StringBuilder result
) {
boolean hasReceiver = receiverType != null;
tdSpace(result);
String receiver = "";
if (hasReceiver) {
boolean error = false;
if (isErrorPosition.apply(ConstraintPosition.RECEIVER_POSITION)) {
error = true;
}
receiver = "receiver: " + strong(getTypeRenderer().render(receiverType), error);
}
td(result, receiver);
td(result, hasReceiver ? "arguments: " : "");
if (argumentTypes.isEmpty()) {
tdBold(result, "( )");
return;
}
td(result, strong("("));
int i = 0;
for (Iterator<JetType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) {
JetType argumentType = iterator.next();
boolean error = false;
if (isErrorPosition.apply(ConstraintPosition.getValueParameterPosition(i))) {
error = true;
}
String renderedArgument = getTypeRenderer().render(argumentType);
tdRight(result, strong(renderedArgument, error) + (iterator.hasNext() ? strong(",") : ""));
i++;
}
td(result, strong(")"));
}
public static HtmlTabledDescriptorRenderer create() {
return new HtmlTabledDescriptorRenderer();
}
protected HtmlTabledDescriptorRenderer() {
super();
}
private static final DescriptorRenderer.ValueParametersHandler VALUE_PARAMETERS_HANDLER = new DescriptorRenderer.ValueParametersHandler() {
@Override
public void appendBeforeValueParameter(@NotNull ValueParameterDescriptor parameter, @NotNull StringBuilder stringBuilder) {
stringBuilder.append("<td align=\"right\" style=\"white-space:nowrap;font-weight:bold;\">");
}
@Override
public void appendAfterValueParameter(@NotNull ValueParameterDescriptor parameter, @NotNull StringBuilder stringBuilder) {
boolean last = ((FunctionDescriptor) parameter.getContainingDeclaration()).getValueParameters().size() - 1 == parameter.getIndex();
if (!last) {
stringBuilder.append(",");
}
stringBuilder.append("</td>");
}
@Override
public void appendBeforeValueParameters(@NotNull FunctionDescriptor function, @NotNull StringBuilder stringBuilder) {
stringBuilder.append("</td>");
if (function.getValueParameters().isEmpty()) {
tdBold(stringBuilder, "( )");
}
else {
tdBold(stringBuilder, "(");
}
}
@Override
public void appendAfterValueParameters(@NotNull FunctionDescriptor function, @NotNull StringBuilder stringBuilder) {
if (!function.getValueParameters().isEmpty()) {
tdBold(stringBuilder, ")");
}
stringBuilder.append("<td style=\"white-space:nowrap;font-weight:bold;\">");
}
};
public static final DescriptorRenderer DESCRIPTOR_IN_TABLE = new DescriptorRendererBuilder()
.setWithDefinedIn(false)
.setModifiers()
.setValueParametersHandler(VALUE_PARAMETERS_HANDLER)
.setTextFormat(DescriptorRenderer.TextFormat.HTML).build();
private static void td(StringBuilder builder, String text) {
builder.append("<td style=\"white-space:nowrap;\">").append(text).append("</td>");
}
private static void tdSpace(StringBuilder builder) {
builder.append("<td width=\"10%\"></td>");
}
private static void tdColspan(StringBuilder builder, String text, int colspan) {
builder.append("<td colspan=\"").append(colspan).append("\" style=\"white-space:nowrap;\">").append(text).append("</td>");
}
private static void tdBold(StringBuilder builder, String text) {
builder.append("<td style=\"white-space:nowrap;font-weight:bold;\">").append(text).append("</td>");
}
private static void tdRight(StringBuilder builder, String text) {
builder.append("<td align=\"right\" style=\"white-space:nowrap;\">").append(text).append("</td>");
}
private static void tdRightBoldColspan(StringBuilder builder, int colspan, String text) {
builder.append("<td align=\"right\" colspan=\"").append(colspan).append("\" style=\"white-space:nowrap;font-weight:bold;\">").append(text).append("</td>");
}
public static String tableForTypes(String message, String firstDescription, TextElementType firstType, String secondDescription, TextElementType secondType) {
StringBuilder result = new StringBuilder();
result.append("<html>").append(message);
result.append("<table><tr><td>").append(firstDescription).append("</td><td>");
renderText(result, firstType, "{0}");
result.append("</td></tr><tr><td>").append(secondDescription).append("</td><td>");
renderText(result, secondType, "{1}");
result.append("</td></tr></table></html>");
return result.toString();
}
}
@@ -0,0 +1,116 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages;
import org.jetbrains.jet.lang.diagnostics.rendering.DiagnosticFactoryToRendererMap;
import org.jetbrains.jet.lang.diagnostics.rendering.DiagnosticRenderer;
import org.jetbrains.jet.lang.diagnostics.rendering.DispatchingDiagnosticRenderer;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.RENDER_CLASS_OR_OBJECT;
import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.STRING;
import static org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TextElementType;
import static org.jetbrains.jet.lang.resolve.java.diagnostics.ErrorsJvm.ACCIDENTAL_OVERRIDE;
import static org.jetbrains.jet.lang.resolve.java.diagnostics.ErrorsJvm.CONFLICTING_JVM_DECLARATIONS;
import static org.jetbrains.jet.plugin.highlighter.HtmlTabledDescriptorRenderer.tableForTypes;
import static org.jetbrains.jet.plugin.highlighter.IdeRenderers.*;
/**
* @see DefaultErrorMessages
*/
public class IdeErrorMessages {
public static final DiagnosticFactoryToRendererMap MAP = new DiagnosticFactoryToRendererMap();
public static final DiagnosticRenderer<Diagnostic> RENDERER = new DispatchingDiagnosticRenderer(ContainerUtil.concat(false, DefaultErrorMessages.MAPS, MAP));
static {
MAP.put(TYPE_MISMATCH, "<html>Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table></html>",
HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(ASSIGN_OPERATOR_AMBIGUITY, "<html>Assignment operators ambiguity. All these functions match.<ul>{0}</ul></table></html>",
HTML_AMBIGUOUS_CALLS);
MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "<html>Type inference failed: {0}</html>", HTML_TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "<html>Type inference failed: {0}</html>", HTML_TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER);
MAP.put(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH, "<html>Type inference failed: {0}</html>", HTML_TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER);
MAP.put(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, tableForTypes("Type inference failed. Expected type mismatch: ",
"required: ", TextElementType.STRONG,
"found: ", TextElementType.ERROR), HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "<html>{0}</html>", HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER);
MAP.put(WRONG_SETTER_PARAMETER_TYPE, "<html>Setter parameter type must be equal to the type of the property." +
"<table><tr><td>Expected:</td><td>{0}</td></tr>" +
"<tr><td>Found:</td><td>{1}</td></tr></table></html>", HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(WRONG_GETTER_RETURN_TYPE, "<html>Getter return type must be equal to the type of the property." +
"<table><tr><td>Expected:</td><td>{0}</td></tr>" +
"<tr><td>Found:</td><td>{1}</td></tr></table></html>", HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(ITERATOR_AMBIGUITY, "<html>Method ''iterator()'' is ambiguous for this expression.<ul>{0}</ul></html>", HTML_AMBIGUOUS_CALLS);
MAP.put(UPPER_BOUND_VIOLATED, "<html>Type argument is not within its bounds." +
"<table><tr><td>Expected:</td><td>{0}</td></tr>" +
"<tr><td>Found:</td><td>{1}</td></tr></table></html>", HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(TYPE_MISMATCH_IN_FOR_LOOP, "<html>Loop parameter type mismatch." +
"<table><tr><td>Iterated values:</td><td>{0}</td></tr>" +
"<tr><td>Parameter:</td><td>{1}</td></tr></table></html>", HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, "<html>Return type is ''{0}'', which is not a subtype of overridden<br/>" +
"{1}</html>", HTML_RENDER_RETURN_TYPE, DescriptorRenderer.HTML);
MAP.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, "<html>Var-property type is ''{0}'', which is not a type of overridden<br/>" +
"{1}</html>", HTML_RENDER_RETURN_TYPE, DescriptorRenderer.HTML);
MAP.put(VAR_OVERRIDDEN_BY_VAL, "<html>Val-property cannot override var-property<br />" +
"{1}</html>", DescriptorRenderer.HTML, DescriptorRenderer.HTML);
MAP.put(ABSTRACT_MEMBER_NOT_IMPLEMENTED, "<html>{0} must be declared abstract or implement abstract member<br/>" +
"{1}</html>", RENDER_CLASS_OR_OBJECT,
DescriptorRenderer.HTML);
MAP.put(MANY_IMPL_MEMBER_NOT_IMPLEMENTED, "<html>{0} must override {1}<br />because it inherits many implementations of it</html>",
RENDER_CLASS_OR_OBJECT, DescriptorRenderer.HTML);
MAP.put(CONFLICTING_OVERLOADS, "<html>''{0}''<br />is already defined in {1}</html>",
DescriptorRenderer.HTML_COMPACT_WITH_MODIFIERS, STRING);
MAP.put(RESULT_TYPE_MISMATCH, "<html>Function return type mismatch." +
"<table><tr><td>Expected:</td><td>{1}</td></tr>" +
"<tr><td>Found:</td><td>{2}</td></tr></table></html>", STRING, HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(OVERLOAD_RESOLUTION_AMBIGUITY, "<html>Overload resolution ambiguity. All these functions match. <ul>{0}</ul></html>", HTML_AMBIGUOUS_CALLS);
MAP.put(NONE_APPLICABLE, "<html>None of the following functions can be called with the arguments supplied. <ul>{0}</ul></html>",
HTML_NONE_APPLICABLE_CALLS);
MAP.put(CANNOT_COMPLETE_RESOLVE, "<html>Cannot choose among the following candidates without completing type inference: <ul>{0}</ul></html>", HTML_AMBIGUOUS_CALLS);
MAP.put(UNRESOLVED_REFERENCE_WRONG_RECEIVER, "<html>Unresolved reference. <br/> None of the following candidates is applicable because of receiver type mismatch: <ul>{0}</ul></html>", HTML_AMBIGUOUS_CALLS);
MAP.put(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, "<html>Overload resolution ambiguity on method ''{0}''. All these functions match. <ul>{1}</ul></html>", STRING, HTML_AMBIGUOUS_CALLS);
MAP.put(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, "<html>Property delegate must have a ''{0}'' method. None of the following functions is suitable. <ul>{1}</ul></html>",
STRING, HTML_NONE_APPLICABLE_CALLS);
MAP.put(CONFLICTING_JVM_DECLARATIONS, "<html>Platform declaration clash: {0}</html>", HTML_CONFLICTING_JVM_DECLARATIONS_DATA);
MAP.put(ACCIDENTAL_OVERRIDE, "<html>Accidental override: {0}</html>", HTML_CONFLICTING_JVM_DECLARATIONS_DATA);
MAP.setImmutable();
}
private IdeErrorMessages() {
}
}
@@ -0,0 +1,154 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.java.diagnostics.ConflictingJvmDeclarationsData;
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import org.jetbrains.jet.renderer.Renderer;
import java.util.Collection;
import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.*;
import static org.jetbrains.jet.plugin.highlighter.renderersUtil.RenderersUtilPackage.renderResolvedCall;
public class IdeRenderers {
private static final String RED_TEMPLATE = "<font color=red><b>%s</b></font>";
private static final String STRONG_TEMPLATE = "<b>%s</b>";
@NotNull
public static String strong(Object o) {
return String.format(STRONG_TEMPLATE, o);
}
@NotNull
public static String error(Object o) {
return String.format(RED_TEMPLATE, o);
}
@NotNull
public static String strong(Object o, boolean error) {
return String.format(error ? RED_TEMPLATE : STRONG_TEMPLATE, o);
}
public static final Renderer<Collection<? extends ResolvedCall<?>>> HTML_AMBIGUOUS_CALLS =
new Renderer<Collection<? extends ResolvedCall<?>>>() {
@NotNull
@Override
public String render(@NotNull Collection<? extends ResolvedCall<?>> calls) {
StringBuilder stringBuilder = new StringBuilder("");
for (ResolvedCall<?> call : calls) {
stringBuilder.append("<li>");
stringBuilder.append(DescriptorRenderer.HTML.render(call.getResultingDescriptor()));
stringBuilder.append("</li>");
}
return stringBuilder.toString();
}
};
public static final Renderer<JetType> HTML_RENDER_TYPE = new Renderer<JetType>() {
@NotNull
@Override
public String render(@NotNull JetType type) {
return DescriptorRenderer.HTML.renderType(type);
}
};
public static final Renderer<Collection<? extends ResolvedCall<?>>> HTML_NONE_APPLICABLE_CALLS =
new Renderer<Collection<? extends ResolvedCall<?>>>() {
@NotNull
@Override
public String render(@NotNull Collection<? extends ResolvedCall<?>> calls) {
StringBuilder stringBuilder = new StringBuilder("");
for (ResolvedCall<?> resolvedCall : calls) {
stringBuilder.append("<li>");
stringBuilder.append(renderResolvedCall(resolvedCall));
stringBuilder.append("</li>");
}
return stringBuilder.toString();
}
};
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderConflictingSubstitutionsInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderTypeConstructorMismatchError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderNoInformationForParameterError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<InferenceErrorData> HTML_TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER =
new Renderer<InferenceErrorData>() {
@NotNull
@Override
public String render(@NotNull InferenceErrorData inferenceErrorData) {
return renderUpperBoundViolatedInferenceError(inferenceErrorData, HtmlTabledDescriptorRenderer.create()).toString();
}
};
public static final Renderer<CallableMemberDescriptor> HTML_RENDER_RETURN_TYPE = new Renderer<CallableMemberDescriptor>() {
@NotNull
@Override
public String render(@NotNull CallableMemberDescriptor object) {
JetType returnType = object.getReturnType();
assert returnType != null;
return DescriptorRenderer.HTML.renderType(returnType);
}
};
public static final Renderer<ConflictingJvmDeclarationsData> HTML_CONFLICTING_JVM_DECLARATIONS_DATA = new Renderer<ConflictingJvmDeclarationsData>() {
@NotNull
@Override
public String render(@NotNull ConflictingJvmDeclarationsData data) {
StringBuilder sb = new StringBuilder("<ul>");
for (JvmDeclarationOrigin origin : data.getSignatureOrigins()) {
DeclarationDescriptor descriptor = origin.getDescriptor();
if (descriptor != null) {
sb.append("<li>").append(DescriptorRenderer.HTML_COMPACT_WITH_MODIFIERS.render(descriptor)).append("</li>\n");
}
}
sb.append("</ul>");
return ("The following declarations have the same JVM signature (<code>" + data.getSignature().getName() + data.getSignature().getDesc() + "</code>):<br/>\n" + sb).trim();
}
};
}
@@ -0,0 +1,99 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.kdoc.lexer.KDocTokens;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.HashMap;
import java.util.Map;
public class JetHighlighter extends SyntaxHighlighterBase {
private static final Map<IElementType, TextAttributesKey> keys1;
private static final Map<IElementType, TextAttributesKey> keys2;
@Override
@NotNull
public Lexer getHighlightingLexer() {
return new JetHighlightingLexer();
}
@Override
@NotNull
public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
return pack(keys1.get(tokenType), keys2.get(tokenType));
}
static {
keys1 = new HashMap<IElementType, TextAttributesKey>();
keys2 = new HashMap<IElementType, TextAttributesKey>();
fillMap(keys1, JetTokens.KEYWORDS, JetHighlightingColors.KEYWORD);
keys1.put(JetTokens.AS_SAFE, JetHighlightingColors.KEYWORD);
keys1.put(JetTokens.LABEL_IDENTIFIER, JetHighlightingColors.LABEL);
keys1.put(JetTokens.INTEGER_LITERAL, JetHighlightingColors.NUMBER);
keys1.put(JetTokens.FLOAT_LITERAL, JetHighlightingColors.NUMBER);
fillMap(keys1,
TokenSet.andNot(JetTokens.OPERATIONS,
TokenSet.orSet(
TokenSet.create(JetTokens.IDENTIFIER, JetTokens.LABEL_IDENTIFIER),
JetTokens.KEYWORDS)),
JetHighlightingColors.OPERATOR_SIGN);
keys1.put(JetTokens.LPAR, JetHighlightingColors.PARENTHESIS);
keys1.put(JetTokens.RPAR, JetHighlightingColors.PARENTHESIS);
keys1.put(JetTokens.LBRACE, JetHighlightingColors.BRACES);
keys1.put(JetTokens.RBRACE, JetHighlightingColors.BRACES);
keys1.put(JetTokens.LBRACKET, JetHighlightingColors.BRACKETS);
keys1.put(JetTokens.RBRACKET, JetHighlightingColors.BRACKETS);
keys1.put(JetTokens.COMMA, JetHighlightingColors.COMMA);
keys1.put(JetTokens.SEMICOLON, JetHighlightingColors.SEMICOLON);
keys1.put(JetTokens.DOT, JetHighlightingColors.DOT);
keys1.put(JetTokens.ARROW, JetHighlightingColors.ARROW);
keys1.put(JetTokens.OPEN_QUOTE, JetHighlightingColors.STRING);
keys1.put(JetTokens.CLOSING_QUOTE, JetHighlightingColors.STRING);
keys1.put(JetTokens.REGULAR_STRING_PART, JetHighlightingColors.STRING);
keys1.put(JetTokens.LONG_TEMPLATE_ENTRY_END, JetHighlightingColors.STRING_ESCAPE);
keys1.put(JetTokens.LONG_TEMPLATE_ENTRY_START, JetHighlightingColors.STRING_ESCAPE);
keys1.put(JetTokens.SHORT_TEMPLATE_ENTRY_START, JetHighlightingColors.STRING_ESCAPE);
keys1.put(JetTokens.ESCAPE_SEQUENCE, JetHighlightingColors.STRING_ESCAPE);
keys1.put(JetTokens.CHARACTER_LITERAL, JetHighlightingColors.STRING);
keys1.put(JetTokens.EOL_COMMENT, JetHighlightingColors.LINE_COMMENT);
keys1.put(JetTokens.SHEBANG_COMMENT, JetHighlightingColors.LINE_COMMENT);
keys1.put(JetTokens.BLOCK_COMMENT, JetHighlightingColors.BLOCK_COMMENT);
keys1.put(JetTokens.DOC_COMMENT, JetHighlightingColors.DOC_COMMENT);
fillMap(keys1, KDocTokens.KDOC_HIGHLIGHT_TOKENS, JetHighlightingColors.DOC_COMMENT);
keys1.put(KDocTokens.TAG_NAME, JetHighlightingColors.KDOC_TAG);
keys2.put(KDocTokens.TAG_NAME, JetHighlightingColors.DOC_COMMENT);
keys1.put(TokenType.BAD_CHARACTER, JetHighlightingColors.BAD_CHARACTER);
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.ide.highlighter.JavaHighlightingColors;
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
import com.intellij.openapi.editor.HighlighterColors;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;
public class JetHighlightingColors {
// default keys (mostly syntax elements)
public static final TextAttributesKey KEYWORD = createTextAttributesKey("KOTLIN_KEYWORD", JavaHighlightingColors.KEYWORD);
public static final TextAttributesKey BUILTIN_ANNOTATION = createTextAttributesKey("KOTLIN_BUILTIN_ANNOTATION", JavaHighlightingColors.KEYWORD);
public static final TextAttributesKey NUMBER = createTextAttributesKey("KOTLIN_NUMBER", DefaultLanguageHighlighterColors.NUMBER);
public static final TextAttributesKey STRING = createTextAttributesKey("KOTLIN_STRING", DefaultLanguageHighlighterColors.STRING);
public static final TextAttributesKey STRING_ESCAPE = createTextAttributesKey("KOTLIN_STRING_ESCAPE", DefaultLanguageHighlighterColors.VALID_STRING_ESCAPE);
public static final TextAttributesKey INVALID_STRING_ESCAPE = createTextAttributesKey("KOTLIN_INVALID_STRING_ESCAPE", DefaultLanguageHighlighterColors.INVALID_STRING_ESCAPE);
public static final TextAttributesKey OPERATOR_SIGN = createTextAttributesKey("KOTLIN_OPERATION_SIGN", DefaultLanguageHighlighterColors.OPERATION_SIGN);
public static final TextAttributesKey PARENTHESIS = createTextAttributesKey("KOTLIN_PARENTHESIS", DefaultLanguageHighlighterColors.PARENTHESES);
public static final TextAttributesKey BRACES = createTextAttributesKey("KOTLIN_BRACES", DefaultLanguageHighlighterColors.BRACES);
public static final TextAttributesKey BRACKETS = createTextAttributesKey("KOTLIN_BRACKETS", DefaultLanguageHighlighterColors.BRACKETS);
public static final TextAttributesKey FUNCTION_LITERAL_BRACES_AND_ARROW = createTextAttributesKey("KOTLIN_FUNCTION_LITERAL_BRACES_AND_ARROW");
public static final TextAttributesKey COMMA = createTextAttributesKey("KOTLIN_COMMA", DefaultLanguageHighlighterColors.COMMA);
public static final TextAttributesKey SEMICOLON = createTextAttributesKey("KOTLIN_SEMICOLON", DefaultLanguageHighlighterColors.SEMICOLON);
public static final TextAttributesKey DOT = createTextAttributesKey("KOTLIN_DOT", DefaultLanguageHighlighterColors.DOT);
public static final TextAttributesKey SAFE_ACCESS = createTextAttributesKey("KOTLIN_SAFE_ACCESS", DefaultLanguageHighlighterColors.DOT);
public static final TextAttributesKey ARROW = createTextAttributesKey("KOTLIN_ARROW", PARENTHESIS);
public static final TextAttributesKey LINE_COMMENT = createTextAttributesKey("KOTLIN_LINE_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT);
public static final TextAttributesKey BLOCK_COMMENT = createTextAttributesKey("KOTLIN_BLOCK_COMMENT", DefaultLanguageHighlighterColors.BLOCK_COMMENT);
public static final TextAttributesKey DOC_COMMENT = createTextAttributesKey("KOTLIN_DOC_COMMENT", DefaultLanguageHighlighterColors.DOC_COMMENT);
public static final TextAttributesKey KDOC_TAG = createTextAttributesKey("KDOC_TAG_NAME", DefaultLanguageHighlighterColors.DOC_COMMENT_TAG);
public static final TextAttributesKey KDOC_TAG_VALUE = createTextAttributesKey("KDOC_TAG_VALUE", DefaultLanguageHighlighterColors.DOC_COMMENT_TAG_VALUE);
// class kinds
public static final TextAttributesKey CLASS = createTextAttributesKey("KOTLIN_CLASS", CodeInsightColors.CLASS_NAME_ATTRIBUTES);
public static final TextAttributesKey TYPE_PARAMETER = createTextAttributesKey("KOTLIN_TYPE_PARAMETER", CodeInsightColors.TYPE_PARAMETER_NAME_ATTRIBUTES);
public static final TextAttributesKey ABSTRACT_CLASS = createTextAttributesKey("KOTLIN_ABSTRACT_CLASS", CodeInsightColors.ABSTRACT_CLASS_NAME_ATTRIBUTES);
public static final TextAttributesKey TRAIT = createTextAttributesKey("KOTLIN_TRAIT", CodeInsightColors.INTERFACE_NAME_ATTRIBUTES);
public static final TextAttributesKey ANNOTATION = createTextAttributesKey("KOTLIN_ANNOTATION", CodeInsightColors.ANNOTATION_NAME_ATTRIBUTES);
public static final TextAttributesKey OBJECT = createTextAttributesKey("KOTLIN_OBJECT", CLASS);
// variable kinds
public static final TextAttributesKey MUTABLE_VARIABLE = createTextAttributesKey("KOTLIN_MUTABLE_VARIABLE");
public static final TextAttributesKey LOCAL_VARIABLE = createTextAttributesKey("KOTLIN_LOCAL_VARIABLE", CodeInsightColors.LOCAL_VARIABLE_ATTRIBUTES);
public static final TextAttributesKey PARAMETER = createTextAttributesKey("KOTLIN_PARAMETER", CodeInsightColors.PARAMETER_ATTRIBUTES);
public static final TextAttributesKey WRAPPED_INTO_REF = createTextAttributesKey("KOTLIN_WRAPPED_INTO_REF", CodeInsightColors.IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES);
public static final TextAttributesKey INSTANCE_PROPERTY = createTextAttributesKey("KOTLIN_INSTANCE_PROPERTY", CodeInsightColors.INSTANCE_FIELD_ATTRIBUTES);
public static final TextAttributesKey PACKAGE_PROPERTY = createTextAttributesKey("KOTLIN_PACKAGE_PROPERTY", CodeInsightColors.STATIC_FIELD_ATTRIBUTES);
public static final TextAttributesKey PROPERTY_WITH_BACKING_FIELD = createTextAttributesKey("KOTLIN_PROPERTY_WITH_BACKING_FIELD");
public static final TextAttributesKey BACKING_FIELD_ACCESS = createTextAttributesKey("KOTLIN_BACKING_FIELD_ACCESS");
public static final TextAttributesKey EXTENSION_PROPERTY = createTextAttributesKey("KOTLIN_EXTENSION_PROPERTY");
// functions
public static final TextAttributesKey FUNCTION_LITERAL_DEFAULT_PARAMETER = createTextAttributesKey("KOTLIN_CLOSURE_DEFAULT_PARAMETER");
public static final TextAttributesKey FUNCTION_DECLARATION = createTextAttributesKey("KOTLIN_FUNCTION_DECLARATION", CodeInsightColors.METHOD_DECLARATION_ATTRIBUTES);
public static final TextAttributesKey FUNCTION_CALL = createTextAttributesKey("KOTLIN_FUNCTION_CALL", CodeInsightColors.METHOD_CALL_ATTRIBUTES);
public static final TextAttributesKey PACKAGE_FUNCTION_CALL = createTextAttributesKey("KOTLIN_PACKAGE_FUNCTION_CALL", CodeInsightColors.STATIC_METHOD_ATTRIBUTES);
public static final TextAttributesKey EXTENSION_FUNCTION_CALL = createTextAttributesKey("KOTLIN_EXTENSION_FUNCTION_CALL");
public static final TextAttributesKey CONSTRUCTOR_CALL = createTextAttributesKey("KOTLIN_CONSTRUCTOR", CodeInsightColors.CONSTRUCTOR_CALL_ATTRIBUTES);
public static final TextAttributesKey VARIABLE_AS_FUNCTION_CALL = createTextAttributesKey("KOTLIN_VARIABLE_AS_FUNCTION");
public static final TextAttributesKey VARIABLE_AS_FUNCTION_LIKE_CALL = createTextAttributesKey("KOTLIN_VARIABLE_AS_FUNCTION_LIKE");
// other
public static final TextAttributesKey BAD_CHARACTER = createTextAttributesKey("KOTLIN_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER);
public static final TextAttributesKey AUTO_CASTED_VALUE = createTextAttributesKey("KOTLIN_AUTO_CASTED_VALUE");
public static final TextAttributesKey LABEL = createTextAttributesKey("KOTLIN_LABEL");
public static final TextAttributesKey DEBUG_INFO = createTextAttributesKey("KOTLIN_DEBUG_INFO");
public static final TextAttributesKey RESOLVED_TO_ERROR = createTextAttributesKey("KOTLIN_RESOLVED_TO_ERROR");
private JetHighlightingColors() {
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lexer.LayeredLexer;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.jet.kdoc.lexer.KDocLexer;
import org.jetbrains.jet.lexer.JetLexer;
import org.jetbrains.jet.lexer.JetTokens;
public class JetHighlightingLexer extends LayeredLexer {
public JetHighlightingLexer() {
super(new JetLexer());
registerSelfStoppingLayer(new KDocLexer(), new IElementType[]{JetTokens.DOC_COMMENT}, IElementType.EMPTY_ARRAY);
}
}
@@ -0,0 +1,285 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension;
import com.intellij.codeInsight.intention.EmptyIntentionAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.MultiRangeReference;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages;
import org.jetbrains.jet.lang.psi.JetCodeFragment;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.Diagnostics;
import org.jetbrains.jet.plugin.ProjectRootsUtil;
import org.jetbrains.jet.plugin.actions.internal.KotlinInternalMode;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.configuration.JetModuleTypeManager;
import org.jetbrains.jet.plugin.quickfix.JetIntentionActionsFactory;
import org.jetbrains.jet.plugin.quickfix.QuickFixes;
import java.util.Collection;
import java.util.List;
public class JetPsiChecker implements Annotator, HighlightRangeExtension {
private static boolean isNamesHighlightingEnabled = true;
@TestOnly
public static void setNamesHighlightingEnabled(boolean namesHighlightingEnabled) {
isNamesHighlightingEnabled = namesHighlightingEnabled;
}
public static boolean isNamesHighlightingEnabled() {
return isNamesHighlightingEnabled;
}
static void highlightName(@NotNull AnnotationHolder holder,
@NotNull PsiElement psiElement,
@NotNull TextAttributesKey attributesKey) {
if (isNamesHighlightingEnabled()) {
holder.createInfoAnnotation(psiElement, null).setTextAttributes(attributesKey);
}
}
private static HighlightingVisitor[] getBeforeAnalysisVisitors(AnnotationHolder holder) {
return new HighlightingVisitor[]{
new SoftKeywordsHighlightingVisitor(holder),
new LabelsHighlightingVisitor(holder),
};
}
private static HighlightingVisitor[] getAfterAnalysisVisitor(AnnotationHolder holder, BindingContext bindingContext) {
return new AfterAnalysisHighlightingVisitor[]{
new PropertiesHighlightingVisitor(holder, bindingContext),
new FunctionsHighlightingVisitor(holder, bindingContext),
new VariablesHighlightingVisitor(holder, bindingContext),
new TypeKindHighlightingVisitor(holder, bindingContext),
new DeprecatedAnnotationVisitor(holder, bindingContext),
};
}
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if (!(ProjectRootsUtil.isInSource(element) || element.getContainingFile() instanceof JetCodeFragment)
|| JetModuleTypeManager.getInstance().isKtFileInGradleProjectInWrongFolder(element)) {
return;
}
for (HighlightingVisitor visitor : getBeforeAnalysisVisitors(holder)) {
element.accept(visitor);
}
JetFile file = (JetFile) element.getContainingFile();
AnalyzeExhaust analyzeExhaust = ResolvePackage.getAnalysisResults(file);
if (analyzeExhaust.isError()) {
throw new ProcessCanceledException(analyzeExhaust.getError());
}
BindingContext bindingContext = analyzeExhaust.getBindingContext();
for (HighlightingVisitor visitor : getAfterAnalysisVisitor(holder, bindingContext)) {
element.accept(visitor);
}
annotateElement(element, holder, bindingContext.getDiagnostics());
}
public static void annotateElement(PsiElement element, AnnotationHolder holder, Diagnostics diagnostics) {
if (ProjectRootsUtil.isInSource(element, /* includeLibrarySources = */ false) || element.getContainingFile() instanceof JetCodeFragment) {
ElementAnnotator elementAnnotator = new ElementAnnotator(element, holder);
for (Diagnostic diagnostic : diagnostics.forElement(element)) {
elementAnnotator.registerDiagnosticAnnotations(diagnostic);
}
}
}
@Override
public boolean isForceHighlightParents(@NotNull PsiFile file) {
return file instanceof JetFile;
}
private static class ElementAnnotator {
private final PsiElement element;
private final AnnotationHolder holder;
private boolean isMarkedWithRedeclaration;
ElementAnnotator(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
this.element = element;
this.holder = holder;
}
void registerDiagnosticAnnotations(@NotNull Diagnostic diagnostic) {
if (!diagnostic.isValid()) return;
assert diagnostic.getPsiElement() == element;
List<TextRange> textRanges = diagnostic.getTextRanges();
if (diagnostic.getSeverity() == Severity.ERROR) {
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
JetReferenceExpression referenceExpression = (JetReferenceExpression)diagnostic.getPsiElement();
PsiReference reference = referenceExpression.getReference();
if (reference instanceof MultiRangeReference) {
MultiRangeReference mrr = (MultiRangeReference)reference;
for (TextRange range : mrr.getRanges()) {
Annotation annotation = holder.createErrorAnnotation(range.shiftRight(referenceExpression.getTextOffset()), getDefaultMessage(diagnostic));
setUpAnnotation(diagnostic, annotation, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
}
else {
for (TextRange textRange : textRanges) {
Annotation annotation = holder.createErrorAnnotation(textRange, getDefaultMessage(diagnostic));
setUpAnnotation(diagnostic, annotation, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
}
return;
}
if (diagnostic.getFactory() == Errors.ILLEGAL_ESCAPE) {
for (TextRange textRange : diagnostic.getTextRanges()) {
Annotation annotation = holder.createErrorAnnotation(textRange, getDefaultMessage(diagnostic));
annotation.setTooltip(getMessage(diagnostic));
annotation.setTextAttributes(JetHighlightingColors.INVALID_STRING_ESCAPE);
}
return;
}
if (diagnostic.getFactory() == Errors.REDECLARATION) {
if (!isMarkedWithRedeclaration) {
isMarkedWithRedeclaration = true;
Annotation annotation = holder.createErrorAnnotation(diagnostic.getTextRanges().get(0), "");
setUpAnnotation(diagnostic, annotation, null);
}
return;
}
// Generic annotation
for (TextRange textRange : textRanges) {
Annotation errorAnnotation = holder.createErrorAnnotation(textRange, getDefaultMessage(diagnostic));
setUpAnnotation(diagnostic, errorAnnotation,
diagnostic.getFactory() == Errors.INVISIBLE_REFERENCE
? ProblemHighlightType.LIKE_UNKNOWN_SYMBOL
: null);
}
}
else if (diagnostic.getSeverity() == Severity.WARNING) {
for (TextRange textRange : textRanges) {
Annotation annotation = holder.createWarningAnnotation(textRange, getDefaultMessage(diagnostic));
setUpAnnotation(diagnostic, annotation,
Errors.UNUSED_ELEMENT_DIAGNOSTICS.contains(diagnostic.getFactory())
? ProblemHighlightType.LIKE_UNUSED_SYMBOL
: null);
}
}
}
private static void setUpAnnotation(Diagnostic diagnostic, Annotation annotation, @Nullable ProblemHighlightType highlightType) {
annotation.setTooltip(getMessage(diagnostic));
registerQuickFix(annotation, diagnostic);
if (highlightType != null) {
annotation.setHighlightType(highlightType);
}
}
/*
* Add a quick fix if and return modified annotation.
*/
@Nullable
private static Annotation registerQuickFix(@Nullable Annotation annotation, @NotNull Diagnostic diagnostic) {
if (annotation == null) {
return null;
}
Collection<JetIntentionActionsFactory> intentionActionsFactories = QuickFixes.getActionsFactories(diagnostic.getFactory());
for (JetIntentionActionsFactory intentionActionsFactory : intentionActionsFactories) {
if (intentionActionsFactory != null) {
for (IntentionAction action: intentionActionsFactory.createActions(diagnostic)) {
annotation.registerFix(action);
}
}
}
Collection<IntentionAction> actions = QuickFixes.getActions(diagnostic.getFactory());
for (IntentionAction action : actions) {
annotation.registerFix(action);
}
// Making warnings suppressable
if (diagnostic.getSeverity() == Severity.WARNING) {
annotation.setProblemGroup(new KotlinSuppressableWarningProblemGroup(diagnostic.getFactory()));
List<Annotation.QuickFixInfo> fixes = annotation.getQuickFixes();
if (fixes == null || fixes.isEmpty()) {
// if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
annotation.registerFix(new EmptyIntentionAction(diagnostic.getFactory().getName()));
}
}
return annotation;
}
@NotNull
private static String getMessage(@NotNull Diagnostic diagnostic) {
String message = IdeErrorMessages.RENDERER.render(diagnostic);
if (KotlinInternalMode.OBJECT$.getEnabled() || ApplicationManager.getApplication().isUnitTestMode()) {
String factoryName = diagnostic.getFactory().getName();
if (message.startsWith("<html>")) {
message = String.format("<html>[%s] %s", factoryName, message.substring("<html>".length()));
} else {
message = String.format("[%s] %s", factoryName, message);
}
}
if (!message.startsWith("<html>")) {
message = "<html><body>" + XmlStringUtil.escapeString(message) + "</body></html>";
}
return message;
}
@NotNull
private static String getDefaultMessage(@NotNull Diagnostic diagnostic) {
String message = DefaultErrorMessages.RENDERER.render(diagnostic);
if (KotlinInternalMode.OBJECT$.getEnabled() || ApplicationManager.getApplication().isUnitTestMode()) {
return String.format("[%s] %s", diagnostic.getFactory().getName(), message);
}
return message;
}
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.openapi.fileTypes.SingleLazyInstanceSyntaxHighlighterFactory;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import org.jetbrains.annotations.NotNull;
public class JetSyntaxHighlighterFactory extends SingleLazyInstanceSyntaxHighlighterFactory {
@Override
@NotNull
protected SyntaxHighlighter createHighlighter() {
return new JetHighlighter();
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter
import com.intellij.codeInsight.daemon.ProblemHighlightFilter
import com.intellij.psi.PsiFile
import org.jetbrains.jet.plugin.JetFileType
import com.intellij.ide.projectView.impl.ProjectRootsUtil
class KotlinProblemHighlightFilter : ProblemHighlightFilter() {
override fun shouldHighlight(psiFile: PsiFile): Boolean {
return psiFile.getFileType() != JetFileType.INSTANCE || !ProjectRootsUtil.isOutsideSourceRoot(psiFile)
}
}
@@ -0,0 +1,112 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter
import com.intellij.codeInspection.SuppressableProblemGroup
import com.intellij.psi.PsiElement
import com.intellij.codeInspection.SuppressIntentionAction
import org.jetbrains.jet.lang.diagnostics.Severity
import java.util.Collections
import org.jetbrains.jet.plugin.quickfix.KotlinSuppressIntentionAction
import org.jetbrains.jet.lang.psi.*
import org.jetbrains.jet.plugin.quickfix.AnnotationHostKind
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory
import com.intellij.psi.util.PsiTreeUtil
class KotlinSuppressableWarningProblemGroup(
private val diagnosticFactory: DiagnosticFactory<*>
) : SuppressableProblemGroup {
{
assert (diagnosticFactory.getSeverity() == Severity.WARNING)
}
override fun getProblemName() = diagnosticFactory.getName()
override fun getSuppressActions(element: PsiElement?): Array<SuppressIntentionAction> {
if (element == null)
return SuppressIntentionAction.EMPTY_ARRAY
return createSuppressWarningActions(element, diagnosticFactory).copyToArray()
}
}
fun createSuppressWarningActions(element: PsiElement, diagnosticFactory: DiagnosticFactory<*>): List<SuppressIntentionAction> {
if (diagnosticFactory.getSeverity() != Severity.WARNING)
return Collections.emptyList()
val actions = arrayListOf<SuppressIntentionAction>()
var current: PsiElement? = element
var suppressAtStatementAllowed = true
while (current != null) {
if (current is JetDeclaration) {
val declaration = current as JetDeclaration
val kind = DeclarationKindDetector.detect(declaration)
if (kind != null) {
actions.add(KotlinSuppressIntentionAction(declaration, diagnosticFactory, kind))
}
suppressAtStatementAllowed = false
}
else if (current is JetExpression && suppressAtStatementAllowed) {
// Add suppress action at first statement
if ((current as PsiElement).getParent() is JetBlockExpression) {
val expression = current as JetExpression
actions.add(KotlinSuppressIntentionAction(expression, diagnosticFactory,
AnnotationHostKind("statement", "", true)))
suppressAtStatementAllowed = false
}
}
current = current?.getParent()
}
return actions
}
private object DeclarationKindDetector : JetVisitor<AnnotationHostKind?, Unit?>() {
fun detect(declaration: JetDeclaration) = declaration.accept(this, null)
override fun visitDeclaration(d: JetDeclaration, _: Unit?) = null
override fun visitClass(d: JetClass, _: Unit?) = detect(d, if (d.isTrait()) "trait" else "class")
override fun visitClassObject(d: JetClassObject, _: Unit?) = detect(d, "class object",
name = "of " + PsiTreeUtil.getParentOfType(d, javaClass<JetClass>())?.getName())
override fun visitNamedFunction(d: JetNamedFunction, _: Unit?) = detect(d, "fun")
override fun visitProperty(d: JetProperty, _: Unit?) = detect(d, d.getValOrVarNode().getText()!!)
override fun visitMultiDeclaration(d: JetMultiDeclaration, _: Unit?) = detect(d, d.getValOrVarNode()?.getText() ?: "val",
name = d.getEntries().map { it.getName() }.makeString(", ", "(", ")"))
override fun visitTypeParameter(d: JetTypeParameter, _: Unit?) = detect(d, "type parameter", newLineNeeded = false)
override fun visitEnumEntry(d: JetEnumEntry, _: Unit?) = detect(d, "enum entry")
override fun visitParameter(d: JetParameter, _: Unit?) = detect(d, "parameter", newLineNeeded = false)
override fun visitObjectDeclaration(d: JetObjectDeclaration, _: Unit?): AnnotationHostKind? {
if (d.getParent() is JetClassObject) return null
if (d.getParent() is JetObjectLiteralExpression) return null
return detect(d, "object")
}
private fun detect(declaration: JetDeclaration, kind: String, name: String = declaration.getName() ?: "<anonymous>", newLineNeeded: Boolean = true)
= AnnotationHostKind(kind, name, newLineNeeded)
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetExpressionWithLabel;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
class LabelsHighlightingVisitor extends HighlightingVisitor {
LabelsHighlightingVisitor(AnnotationHolder holder) {
super(holder);
}
@Override
public void visitExpressionWithLabel(@NotNull JetExpressionWithLabel expression) {
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
if (targetLabel != null) {
JetPsiChecker.highlightName(holder, targetLabel, JetHighlightingColors.LABEL);
}
}
}
@@ -0,0 +1,97 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.JetThisExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lexer.JetTokens;
class PropertiesHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
PropertiesHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext) {
super(holder, bindingContext);
}
@Override
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
if (expression.getParent() instanceof JetThisExpression) {
return;
}
DeclarationDescriptor target = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
if (!(target instanceof PropertyDescriptor)) {
return;
}
highlightProperty(expression, (PropertyDescriptor) target, false);
if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
JetPsiChecker.highlightName(holder, expression, JetHighlightingColors.BACKING_FIELD_ACCESS);
}
}
@Override
public void visitProperty(@NotNull JetProperty property) {
PsiElement nameIdentifier = property.getNameIdentifier();
if (nameIdentifier == null) return;
VariableDescriptor propertyDescriptor = bindingContext.get(BindingContext.VARIABLE, property);
if (propertyDescriptor instanceof PropertyDescriptor) {
Boolean backingFieldRequired = bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor)propertyDescriptor);
highlightProperty(nameIdentifier, (PropertyDescriptor) propertyDescriptor, Boolean.TRUE.equals(backingFieldRequired));
}
super.visitProperty(property);
}
@Override
public void visitParameter(@NotNull JetParameter parameter) {
PsiElement nameIdentifier = parameter.getNameIdentifier();
if (nameIdentifier == null) return;
PropertyDescriptor propertyDescriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
if (propertyDescriptor != null) {
Boolean backingFieldRequired = bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
highlightProperty(nameIdentifier, propertyDescriptor, Boolean.TRUE.equals(backingFieldRequired));
}
super.visitParameter(parameter);
}
private void highlightProperty(@NotNull PsiElement elementToHighlight,
@NotNull PropertyDescriptor descriptor,
boolean withBackingField) {
boolean inPackage = DescriptorUtils.isTopLevelDeclaration(descriptor);
JetPsiChecker.highlightName(holder, elementToHighlight,
inPackage ? JetHighlightingColors.PACKAGE_PROPERTY : JetHighlightingColors.INSTANCE_PROPERTY
);
if (descriptor.getReceiverParameter() != null) {
JetPsiChecker.highlightName(holder, elementToHighlight, JetHighlightingColors.EXTENSION_PROPERTY);
}
if (withBackingField) {
holder.createInfoAnnotation(
elementToHighlight,
"This property has a backing field")
.setTextAttributes(JetHighlightingColors.PROPERTY_WITH_BACKING_FIELD);
}
}
}
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lexer.JetTokens;
class SoftKeywordsHighlightingVisitor extends HighlightingVisitor {
SoftKeywordsHighlightingVisitor(AnnotationHolder holder) {
super(holder);
}
@Override
public void visitElement(PsiElement element) {
if (element instanceof LeafPsiElement) {
IElementType elementType = ((LeafPsiElement)element).getElementType();
if (JetTokens.SOFT_KEYWORDS.contains(elementType)) {
TextAttributesKey attributes = JetHighlightingColors.KEYWORD;
if (JetTokens.MODIFIER_KEYWORDS.contains(elementType)) {
attributes = JetHighlightingColors.BUILTIN_ANNOTATION;
}
holder.createInfoAnnotation(element, null).setTextAttributes(attributes);
}
if (JetTokens.SAFE_ACCESS.equals(elementType)) {
holder.createInfoAnnotation(element, null).setTextAttributes(JetHighlightingColors.SAFE_ACCESS);
}
}
}
@Override
public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
if (ApplicationManager.getApplication().isUnitTestMode()) return;
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
holder.createInfoAnnotation(functionLiteral.getOpenBraceNode(), null).setTextAttributes(JetHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW);
ASTNode closingBraceNode = functionLiteral.getClosingBraceNode();
if (closingBraceNode != null) {
holder.createInfoAnnotation(closingBraceNode, null).setTextAttributes(JetHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW);
}
ASTNode arrowNode = functionLiteral.getArrowNode();
if (arrowNode != null) {
holder.createInfoAnnotation(arrowNode, null).setTextAttributes(JetHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW);
}
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
class TypeKindHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
TypeKindHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext) {
super(holder, bindingContext);
}
@Override
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
PsiReference ref = expression.getReference();
if (ref == null) return;
if (JetPsiChecker.isNamesHighlightingEnabled()) {
DeclarationDescriptor referenceTarget = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
if (referenceTarget instanceof ConstructorDescriptor) {
referenceTarget = referenceTarget.getContainingDeclaration();
}
if (referenceTarget instanceof ClassDescriptor) {
highlightName(expression, textAttributesKeyForClass((ClassDescriptor) referenceTarget));
}
else if (referenceTarget instanceof TypeParameterDescriptor) {
highlightName(expression, JetHighlightingColors.TYPE_PARAMETER);
}
}
}
@Override
public void visitObjectDeclarationName(@NotNull JetObjectDeclarationName declaration) {
PsiElement nameIdentifier = declaration.getNameIdentifier();
if (nameIdentifier != null) {
highlightName(nameIdentifier, JetHighlightingColors.CLASS);
}
}
@Override
public void visitTypeParameter(@NotNull JetTypeParameter parameter) {
PsiElement identifier = parameter.getNameIdentifier();
if (identifier != null) {
highlightName(identifier, JetHighlightingColors.TYPE_PARAMETER);
}
super.visitTypeParameter(parameter);
}
@Override
public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) {
// Do nothing, the name was already highlighted in visitObjectDeclarationName
}
@Override
public void visitClass(@NotNull JetClass klass) {
PsiElement identifier = klass.getNameIdentifier();
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, klass);
if (identifier != null && classDescriptor != null) {
highlightName(identifier, textAttributesKeyForClass(classDescriptor));
}
super.visitClass(klass);
}
private void highlightName(@NotNull PsiElement whatToHighlight, @NotNull TextAttributesKey textAttributesKey) {
JetPsiChecker.highlightName(holder, whatToHighlight, textAttributesKey);
}
@NotNull
private static TextAttributesKey textAttributesKeyForClass(@NotNull ClassDescriptor descriptor) {
switch (descriptor.getKind()) {
case TRAIT:
return JetHighlightingColors.TRAIT;
case ANNOTATION_CLASS:
return JetHighlightingColors.ANNOTATION;
case OBJECT:
return JetHighlightingColors.OBJECT;
case ENUM_ENTRY:
return JetHighlightingColors.INSTANCE_PROPERTY;
default:
return descriptor.getModality() == Modality.ABSTRACT
? JetHighlightingColors.ABSTRACT_CLASS
: JetHighlightingColors.CLASS;
}
}
}
@@ -0,0 +1,111 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.expressions.CaptureKind;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
class VariablesHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
VariablesHighlightingVisitor(AnnotationHolder holder, BindingContext bindingContext) {
super(holder, bindingContext);
}
@Override
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, expression);
if (target == null) {
return;
}
if (target instanceof ValueParameterDescriptor) {
ValueParameterDescriptor parameterDescriptor = (ValueParameterDescriptor) target;
if (Boolean.TRUE.equals(bindingContext.get(AUTO_CREATED_IT, parameterDescriptor))) {
holder.createInfoAnnotation(expression, "Automatically declared based on the expected type").setTextAttributes(
JetHighlightingColors.FUNCTION_LITERAL_DEFAULT_PARAMETER);
}
}
highlightVariable(expression, target);
super.visitSimpleNameExpression(expression);
}
@Override
public void visitProperty(@NotNull JetProperty property) {
visitVariableDeclaration(property);
super.visitProperty(property);
}
@Override
public void visitParameter(@NotNull JetParameter parameter) {
visitVariableDeclaration(parameter);
super.visitParameter(parameter);
}
@Override
public void visitExpression(@NotNull JetExpression expression) {
JetType autoCast = bindingContext.get(AUTOCAST, expression);
if (autoCast != null) {
holder.createInfoAnnotation(expression, "Automatically cast to " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(autoCast)).setTextAttributes(
JetHighlightingColors.AUTO_CASTED_VALUE);
}
super.visitExpression(expression);
}
private void visitVariableDeclaration(JetNamedDeclaration declaration) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, declaration);
PsiElement nameIdentifier = declaration.getNameIdentifier();
if (nameIdentifier != null && declarationDescriptor != null) {
highlightVariable(nameIdentifier, declarationDescriptor);
}
}
private void highlightVariable(@NotNull PsiElement elementToHighlight, @NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof VariableDescriptor) {
VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
if (variableDescriptor.isVar()) {
JetPsiChecker.highlightName(holder, elementToHighlight, JetHighlightingColors.MUTABLE_VARIABLE);
}
if (bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) == CaptureKind.NOT_INLINE) {
String msg = ((VariableDescriptor) descriptor).isVar()
? "Wrapped into a reference object to be modified when captured in a closure"
: "Value captured in a closure";
holder.createInfoAnnotation(elementToHighlight, msg).setTextAttributes(
JetHighlightingColors.WRAPPED_INTO_REF);
}
if (descriptor instanceof LocalVariableDescriptor) {
JetPsiChecker.highlightName(holder, elementToHighlight, JetHighlightingColors.LOCAL_VARIABLE);
}
if (descriptor instanceof ValueParameterDescriptor) {
JetPsiChecker.highlightName(holder, elementToHighlight, JetHighlightingColors.PARAMETER);
}
}
}
}
@@ -0,0 +1,100 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.highlighter.renderersUtil
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
import org.jetbrains.jet.lang.resolve.calls.callUtil.*
import org.jetbrains.jet.lang.resolve.DescriptorUtils
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.plugin.highlighter.IdeRenderers
import org.jetbrains.jet.lang.types.ErrorUtils
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
fun <D : CallableDescriptor> renderResolvedCall(resolvedCall: ResolvedCall<D>): String {
val htmlRenderer = DescriptorRenderer.HTML_FOR_UNINFERRED_TYPE_PARAMS
val stringBuilder = StringBuilder("")
val indent = "&nbsp;&nbsp;"
fun append(any: Any): StringBuilder = stringBuilder.append(any)
fun renderParameter(parameter: ValueParameterDescriptor): String {
val varargElementType = parameter.getVarargElementType()
val parameterType = varargElementType ?: parameter.getType()
val renderedParameter =
(if (varargElementType != null) "<b>vararg</b> " else "") +
htmlRenderer.renderType(parameterType) +
if (parameter.hasDefaultValue()) " = ..." else ""
if (resolvedCall.hasTypeMismatchErrorOnParameter(parameter)) {
return IdeRenderers.error(renderedParameter)
}
return renderedParameter
}
fun appendTypeParametersSubstitution() {
val parametersToArgumentsMap = resolvedCall.getTypeArguments()
fun TypeParameterDescriptor.isInferred(): Boolean {
val typeArgument = parametersToArgumentsMap[this]
if (typeArgument == null) return false
return !ErrorUtils.isUninferredParameter(typeArgument)
}
val typeParameters = resolvedCall.getCandidateDescriptor().getTypeParameters()
val (inferredTypeParameters, notInferredTypeParameters) = typeParameters.partition { parameter -> parameter.isInferred() }
append("<br/>$indent<i>where</i> ")
if (!notInferredTypeParameters.isEmpty()) {
append(notInferredTypeParameters.map { typeParameter -> IdeRenderers.error(typeParameter.getName()) }.makeString())
append("<i> cannot be inferred</i>")
if (!inferredTypeParameters.isEmpty()) {
append("; ")
}
}
val typeParameterToTypeArgumentMap = resolvedCall.getTypeArguments()
if (!inferredTypeParameters.isEmpty()) {
append(inferredTypeParameters.map { typeParameter ->
"${typeParameter.getName()} = ${htmlRenderer.renderType(typeParameterToTypeArgumentMap[typeParameter]!!)}"
}.makeString())
}
}
val resultingDescriptor = resolvedCall.getResultingDescriptor()
val receiverParameter = resultingDescriptor.getReceiverParameter()
if (receiverParameter != null) {
append(htmlRenderer.renderType(receiverParameter.getType())).append(".")
}
append(resultingDescriptor.getName()).append("(")
append(resultingDescriptor.getValueParameters().map { parameter -> renderParameter(parameter) }.makeString())
append(if (resolvedCall.hasUnmappedArguments()) IdeRenderers.error(")") else ")")
if (!resolvedCall.getCandidateDescriptor().getTypeParameters().isEmpty()) {
appendTypeParametersSubstitution()
append("<i> for </i><br/>$indent")
append(htmlRenderer.render(resolvedCall.getCandidateDescriptor()))
}
else {
append(" <i>defined in</i> ")
val containingDeclaration = resultingDescriptor.getContainingDeclaration()
val fqName = DescriptorUtils.getFqName(containingDeclaration)
append(if (FqName.ROOT.equalsTo(fqName)) "root package" else fqName.asString())
}
return stringBuilder.toString()
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.inspections
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.CustomSuppressableInspectionTool
import com.intellij.psi.PsiElement
import com.intellij.codeInsight.daemon.HighlightDisplayKey
import com.intellij.codeInspection.SuppressIntentionAction
import com.intellij.codeInspection.SuppressManager
public abstract class AbstractKotlinInspection: LocalInspectionTool(), CustomSuppressableInspectionTool {
public override fun getSuppressActions(element: PsiElement?): Array<SuppressIntentionAction>? {
return SuppressManager.getInstance()!!.createSuppressActions(HighlightDisplayKey.find(getShortName())!!)
}
public override fun isSuppressedFor(element: PsiElement): Boolean {
return SuppressManager.getInstance()!!.isSuppressedFor(element, getID())
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.intentions
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.plugin.JetBundle
import org.jetbrains.jet.lang.psi.psiUtil.getParentByTypesAndPredicate
import com.intellij.codeInsight.intention.IntentionAction
public abstract class JetSelfTargetingIntention<T: JetElement>(val key: String, val elementType: Class<T>) : IntentionAction {
private var myText:String = JetBundle.message(key);
protected fun setText(text: String) {
myText = text
}
override fun getText(): String = myText
abstract fun isApplicableTo(element: T): Boolean
open fun isApplicableTo(element: T, editor: Editor): Boolean = isApplicableTo(element)
abstract fun applyTo(element: T, editor: Editor)
protected fun getTarget(editor: Editor, file: PsiFile): T? {
val offset = editor.getCaretModel().getOffset()
return file.findElementAt(offset)?.getParentByTypesAndPredicate(false, elementType) { element -> isApplicableTo(element, editor) }
}
public override fun getFamilyName(): String {
return JetBundle.message(key + ".family")
}
public override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {
return getTarget(editor, file) != null
}
public override fun invoke(project: Project, editor: Editor, file: PsiFile): Unit {
val target = getTarget(editor, file)
assert(target != null, "Intention is not applicable")
applyTo(target!!, editor)
}
override fun startInWriteAction(): Boolean = true
override fun toString(): String = getText()
}
@@ -0,0 +1,212 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.intentions
import org.jetbrains.jet.lang.psi.JetExpression
import com.intellij.openapi.editor.Editor
import org.jetbrains.jet.lang.psi.JetPrefixExpression
import org.jetbrains.jet.lang.psi.JetPostfixExpression
import org.jetbrains.jet.lang.psi.JetBinaryExpression
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression
import org.jetbrains.jet.lang.psi.JetCallExpression
import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall
public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpression>("operator.to.function", javaClass()) {
class object {
private fun isApplicablePrefix(element: JetPrefixExpression): Boolean {
return when (element.getOperationReference().getReferencedNameElementType()) {
JetTokens.PLUS, JetTokens.MINUS, JetTokens.PLUSPLUS, JetTokens.MINUSMINUS, JetTokens.EXCL -> true
else -> false
}
}
private fun isApplicablePostfix(element: JetPostfixExpression): Boolean {
return when (element.getOperationReference().getReferencedNameElementType()) {
JetTokens.PLUSPLUS, JetTokens.MINUSMINUS -> true
else -> false
}
}
private fun isApplicableBinary(element: JetBinaryExpression): Boolean {
return when (element.getOperationReference().getReferencedNameElementType()) {
JetTokens.PLUS, JetTokens.MINUS, JetTokens.MUL, JetTokens.DIV, JetTokens.PERC, JetTokens.RANGE, JetTokens.IN_KEYWORD, JetTokens.NOT_IN, JetTokens.PLUSEQ, JetTokens.MINUSEQ, JetTokens.MULTEQ, JetTokens.DIVEQ, JetTokens.PERCEQ, JetTokens.EQEQ, JetTokens.EXCLEQ, JetTokens.GT, JetTokens.LT, JetTokens.GTEQ, JetTokens.LTEQ -> true
JetTokens.EQ -> element.getLeft() is JetArrayAccessExpression
else -> false
}
}
private fun isApplicableCall(element: JetCallExpression): Boolean {
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element)
val resolvedCall = element.getResolvedCall(bindingContext)
val descriptor = resolvedCall?.getResultingDescriptor()
if (descriptor is FunctionDescriptor && descriptor.getName().asString() == "invoke") {
val parent = element.getParent()
if (parent is JetDotQualifiedExpression && element.getCalleeExpression()?.getText() == "invoke") return false
return !(element.getValueArgumentList() == null && element.getFunctionLiteralArguments().isEmpty())
}
return false
}
private fun convertPrefix(element: JetPrefixExpression): JetExpression {
val op = element.getOperationReference().getReferencedNameElementType()
val base = element.getBaseExpression()!!.getText()
val call = when (op) {
JetTokens.PLUS -> "plus()"
JetTokens.MINUS -> "minus()"
JetTokens.PLUSPLUS -> "inc()"
JetTokens.MINUSMINUS -> "dec()"
JetTokens.EXCL -> "not()"
else -> return element
}
val transformation = "$base.$call"
val transformed = JetPsiFactory(element).createExpression(transformation)
return element.replace(transformed) as JetExpression
}
private fun convertPostFix(element: JetPostfixExpression): JetExpression {
val op = element.getOperationReference().getReferencedNameElementType()
val base = element.getBaseExpression().getText()
val call = when (op) {
JetTokens.PLUSPLUS -> "inc()"
JetTokens.MINUSMINUS -> "dec()"
else -> return element
}
val transformation = "$base.$call"
val transformed = JetPsiFactory(element).createExpression(transformation)
return element.replace(transformed) as JetExpression
}
private fun convertBinary(element: JetBinaryExpression): JetExpression {
val op = element.getOperationReference().getReferencedNameElementType()
val left = element.getLeft()!!
val right = element.getRight()!!
val leftText = left.getText()
val rightText = right.getText()
if (op == JetTokens.EQ) {
if (left is JetArrayAccessExpression) {
convertArrayAccess(left as JetArrayAccessExpression)
}
return element
}
val context = AnalyzerFacadeWithCache.getContextForElement(element)
val functionCandidate = element.getResolvedCall(context)
val functionName = functionCandidate?.getCandidateDescriptor()?.getName().toString()
val elemType = context[BindingContext.EXPRESSION_TYPE, left]
val transformation = when (op) {
JetTokens.PLUS -> "$leftText.plus($rightText)"
JetTokens.MINUS -> "$leftText.minus($rightText)"
JetTokens.MUL -> "$leftText.times($rightText)"
JetTokens.DIV -> "$leftText.div($rightText)"
JetTokens.PERC -> "$leftText.mod($rightText)"
JetTokens.RANGE -> "$leftText.rangeTo($rightText)"
JetTokens.IN_KEYWORD -> "$rightText.contains($leftText)"
JetTokens.NOT_IN -> "!$rightText.contains($leftText)"
JetTokens.PLUSEQ -> if (functionName == "plusAssign") "$leftText.plusAssign($rightText)" else "$leftText = $leftText.plus($rightText)"
JetTokens.MINUSEQ -> if (functionName == "minusAssign") "$leftText.minusAssign($rightText)" else "$leftText = $leftText.minus($rightText)"
JetTokens.MULTEQ -> if (functionName == "multAssign") "$leftText.multAssign($rightText)" else "$leftText = $leftText.mult($rightText)"
JetTokens.DIVEQ -> if (functionName == "divAssign") "$leftText.divAssign($rightText)" else "$leftText = $leftText.div($rightText)"
JetTokens.PERCEQ -> if (functionName == "modAssign") "$leftText.modAssign($rightText)" else "$leftText = $leftText.mod($rightText)"
JetTokens.EQEQ -> if (elemType?.isNullable() ?: true) "$leftText?.equals($rightText) ?: $rightText.identityEquals(null)" else "$leftText.equals($rightText)"
JetTokens.EXCLEQ -> if (elemType?.isNullable() ?: true) "!($leftText?.equals($rightText) ?: $rightText.identityEquals(null))" else "!$leftText.equals($rightText)"
JetTokens.GT -> "$leftText.compareTo($rightText) > 0"
JetTokens.LT -> "$leftText.compareTo($rightText) < 0"
JetTokens.GTEQ -> "$leftText.compareTo($rightText) >= 0"
JetTokens.LTEQ -> "$leftText.compareTo($rightText) <= 0"
else -> return element
}
val transformed = JetPsiFactory(element).createExpression(transformation)
return element.replace(transformed) as JetExpression
}
private fun convertArrayAccess(element: JetArrayAccessExpression): JetExpression {
val parent = element.getParent()
val array = element.getArrayExpression()!!.getText()
val indices = element.getIndicesNode()
val indicesText = indices.getText()?.trim("[","]") ?: throw AssertionError("Indices node of ArrayExpression shouldn't be null: JetArrayAccessExpression = ${element.getText()}")
val transformation : String
val replaced : JetElement
if (parent is JetBinaryExpression && parent.getOperationReference().getReferencedNameElementType() == JetTokens.EQ) {
// part of an assignment
val right = parent.getRight()!!.getText()
transformation = "$array.set($indicesText, $right)"
replaced = parent
}
else {
transformation = "$array.get($indicesText)"
replaced = element
}
val transformed = JetPsiFactory(element).createExpression(transformation)
return replaced.replace(transformed) as JetExpression
}
private fun convertCall(element: JetCallExpression): JetExpression {
val callee = element.getCalleeExpression()!!
val arguments = element.getValueArgumentList()
val argumentString = arguments?.getText()?.trim("(", ")")
val funcLitArgs = element.getFunctionLiteralArguments()
val calleeText = callee.getText()
val transformation = if (argumentString == null) "$calleeText.invoke" else "$calleeText.invoke($argumentString)"
val transformed = JetPsiFactory(element).createExpression(transformation)
funcLitArgs.forEach { transformed.add(it) }
return callee.getParent()!!.replace(transformed) as JetExpression
}
public fun convert(element: JetExpression): JetExpression {
return when (element) {
is JetPrefixExpression -> convertPrefix(element)
is JetPostfixExpression -> convertPostFix(element)
is JetBinaryExpression -> convertBinary(element)
is JetArrayAccessExpression -> convertArrayAccess(element)
is JetCallExpression -> convertCall(element)
else -> element
}
}
}
override fun isApplicableTo(element: JetExpression): Boolean {
return when (element) {
is JetPrefixExpression -> isApplicablePrefix(element)
is JetPostfixExpression -> isApplicablePostfix(element)
is JetBinaryExpression -> isApplicableBinary(element)
is JetArrayAccessExpression -> true
is JetCallExpression -> isApplicableCall(element)
else -> false
}
}
override fun applyTo(element: JetExpression, editor: Editor) {
convert(element)
}
}
@@ -0,0 +1,127 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqNameSafe;
public final class DecompiledNavigationUtils {
private static final Logger LOG = Logger.getInstance(DecompiledNavigationUtils.class);
@Nullable
public static JetDeclaration findDeclarationForReference(
@NotNull Project project,
@NotNull DeclarationDescriptor referencedDescriptor
) {
JetDeclaration declarationFromDecompiledClassFile = getDeclarationFromDecompiledClassFile(project, referencedDescriptor);
if (declarationFromDecompiledClassFile == null) {
return null;
}
return JetSourceNavigationHelper.replaceBySourceDeclarationIfPresent(declarationFromDecompiledClassFile);
}
@Nullable
private static JetDeclaration getDeclarationFromDecompiledClassFile(
@NotNull Project project,
@NotNull DeclarationDescriptor referencedDescriptor
) {
DeclarationDescriptor effectiveReferencedDescriptor = getEffectiveReferencedDescriptor(referencedDescriptor);
VirtualFile virtualFile = findVirtualFileContainingDescriptor(project, effectiveReferencedDescriptor);
if (virtualFile == null || !LibrariesPackage.isKotlinCompiledFile(virtualFile)) return null;
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
if (!(psiFile instanceof JetClsFile)) {
return null;
}
JetDeclaration jetDeclaration = ((JetClsFile) psiFile).getDeclarationForDescriptor(effectiveReferencedDescriptor);
if (jetDeclaration != null) {
return jetDeclaration;
}
else {
LOG.warn("Could not find an element to navigate to for descriptor " + getFqName(effectiveReferencedDescriptor));
}
return null;
}
//TODO: should be done via some generic mechanism
@NotNull
private static DeclarationDescriptor getEffectiveReferencedDescriptor(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof CallableMemberDescriptor) {
return DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
}
return descriptor;
}
/*
Find virtual file which contains the declaration of descriptor we're navigating to.
*/
@Nullable
private static VirtualFile findVirtualFileContainingDescriptor(
@NotNull Project project,
@NotNull DeclarationDescriptor referencedDescriptor
) {
FqName containerFqName = getContainerFqName(referencedDescriptor);
if (containerFqName == null) {
return null;
}
VirtualFileFinder fileFinder = VirtualFileFinder.SERVICE.getInstance(project);
VirtualFile virtualFile = fileFinder.findVirtualFileWithHeader(containerFqName);
if (virtualFile == null) {
return null;
}
return virtualFile;
}
//TODO: navigate to inner classes
@Nullable
private static FqName getContainerFqName(@NotNull DeclarationDescriptor referencedDescriptor) {
ClassOrPackageFragmentDescriptor
containerDescriptor = DescriptorUtils.getParentOfType(referencedDescriptor, ClassOrPackageFragmentDescriptor.class, false);
if (containerDescriptor instanceof PackageFragmentDescriptor) {
return PackageClassUtils.getPackageClassFqName(((PackageFragmentDescriptor) containerDescriptor).getFqName());
}
if (containerDescriptor instanceof ClassDescriptor) {
if (containerDescriptor.getContainingDeclaration() instanceof ClassDescriptor
|| ExpressionTypingUtils.isLocal(containerDescriptor.getContainingDeclaration(), containerDescriptor)) {
return getContainerFqName(containerDescriptor.getContainingDeclaration());
}
return getFqNameSafe(containerDescriptor);
}
return null;
}
private DecompiledNavigationUtils() {
}
}
@@ -0,0 +1,166 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.resolve.MemberComparator
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache
import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.renderer.DescriptorRendererBuilder
import java.util.*
import org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.jet.lang.resolve.DescriptorUtils.isSyntheticClassObject
import org.jetbrains.jet.lang.types.error.MissingDependencyErrorClass
import org.jetbrains.jet.lang.resolve.name.isComponentFunctionName
public fun buildDecompiledText(
classFile: VirtualFile,
resolver: ResolverForDecompiler = DeserializerForDecompiler(classFile)
): DecompiledText {
val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile)
assert(kotlinClass != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile }
val classFqName = kotlinClass!!.getClassName().getFqNameForClassNameWithoutDollars()
val kind = kotlinClass.getClassHeader().kind
val packageFqName = classFqName.parent()
return if (kind == KotlinClassHeader.Kind.PACKAGE_FACADE) {
buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInPackage(packageFqName)))
}
else if (kind == KotlinClassHeader.Kind.CLASS) {
buildDecompiledText(packageFqName, listOf(resolver.resolveTopLevelClass(classFqName)).filterNotNull())
}
else {
throw UnsupportedOperationException("Unknown header kind: " + kind)
}
}
private val DECOMPILED_COMMENT = "/* compiled code */"
public val descriptorRendererForDecompiler: DescriptorRenderer = DescriptorRendererBuilder()
.setWithDefinedIn(false)
.setClassWithPrimaryConstructor(true)
.build()
//TODO: should use more accurate way to identify descriptors
public fun descriptorToKey(descriptor: DeclarationDescriptor): String {
return descriptorRendererForDecompiler.render(descriptor)
}
private data class DecompiledText(val text: String, val renderedDescriptorsToRange: Map<String, TextRange>)
private fun buildDecompiledText(packageFqName: FqName, descriptors: List<DeclarationDescriptor>): DecompiledText {
val builder = StringBuilder()
val renderedDescriptorsToRange = HashMap<String, TextRange>()
fun appendDecompiledTextAndPackageName() {
builder.append("// IntelliJ API Decompiler stub source generated from a class file\n" + "// Implementation of methods is not available")
builder.append("\n\n")
if (!packageFqName.isRoot()) {
builder.append("package ").append(packageFqName).append("\n\n")
}
}
fun sortDeclarations(input: Collection<DeclarationDescriptor>): List<DeclarationDescriptor> {
val r = ArrayList<DeclarationDescriptor>(input)
Collections.sort(r, MemberComparator.INSTANCE)
return r
}
fun saveDescriptorToRange(descriptor: DeclarationDescriptor, startOffset: Int, endOffset: Int) {
renderedDescriptorsToRange[descriptorToKey(descriptor)] = TextRange(startOffset, endOffset)
}
fun appendDescriptor(descriptor: DeclarationDescriptor, indent: String) {
if (descriptor is MissingDependencyErrorClass) {
throw IllegalStateException("${descriptor.javaClass.getSimpleName()} cannot be rendered. FqName: ${descriptor.fullFqName}")
}
val startOffset = builder.length()
val header = if (isEnumEntry(descriptor))
descriptor.getName().asString()
else
descriptorRendererForDecompiler.render(descriptor).replace("= ...", "= " + DECOMPILED_COMMENT)
builder.append(header)
var endOffset = builder.length()
if (descriptor is FunctionDescriptor || descriptor is PropertyDescriptor) {
if ((descriptor as MemberDescriptor).getModality() != Modality.ABSTRACT) {
if (descriptor is FunctionDescriptor) {
builder.append(" { ").append(DECOMPILED_COMMENT).append(" }")
endOffset = builder.length()
}
else {
// descriptor instanceof PropertyDescriptor
builder.append(" ").append(DECOMPILED_COMMENT)
}
}
}
else
if (descriptor is ClassDescriptor && !isEnumEntry(descriptor)) {
builder.append(" {\n")
var firstPassed = false
val subindent = indent + " "
val classObject = descriptor.getClassObjectDescriptor()
if (classObject != null && !isSyntheticClassObject(classObject)) {
firstPassed = true
builder.append(subindent)
appendDescriptor(classObject, subindent)
}
for (member in sortDeclarations(descriptor.getDefaultType().getMemberScope().getAllDescriptors())) {
if (member.getContainingDeclaration() != descriptor) {
continue
}
if (member is CallableMemberDescriptor
&& member.getKind() != CallableMemberDescriptor.Kind.DECLARATION
&& !member.getName().isComponentFunctionName()) {
continue
}
if (firstPassed) {
builder.append("\n")
}
else {
firstPassed = true
}
builder.append(subindent)
appendDescriptor(member, subindent)
}
builder.append(indent).append("}")
endOffset = builder.length()
}
builder.append("\n")
saveDescriptorToRange(descriptor, startOffset, endOffset)
if (descriptor is ClassDescriptor) {
val primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor()
if (primaryConstructor != null) {
saveDescriptorToRange(primaryConstructor, startOffset, endOffset)
}
}
}
appendDecompiledTextAndPackageName()
for (member in sortDeclarations(descriptors)) {
appendDescriptor(member, "")
builder.append("\n")
}
return DecompiledText(builder.toString(), renderedDescriptorsToRange)
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache
import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader
import com.intellij.psi.ClassFileViewProvider
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass
import com.intellij.ide.highlighter.JavaClassFileType
public fun isKotlinCompiledFile(file: VirtualFile): Boolean {
if (isKotlinCompiledFileWithIncompatibleAbiVersion(file)) {
return false
}
val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader()
return header != null && header.syntheticClassKind != KotlinSyntheticClass.Kind.TRAIT_IMPL
}
public fun isKotlinCompiledFileWithIncompatibleAbiVersion(file: VirtualFile): Boolean {
if (file.getExtension() != JavaClassFileType.INSTANCE!!.getDefaultExtension()) {
return false
}
val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader()
return header?.kind == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION
}
public fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean {
if (!isKotlinCompiledFile(file)) {
return false
}
if (ClassFileViewProvider.isInnerClass(file)) {
return true
}
val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader()
return header?.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS
}
@@ -0,0 +1,195 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import org.jetbrains.jet.descriptors.serialization.ClassId
import org.jetbrains.jet.descriptors.serialization.ClassDataFinder
import org.jetbrains.jet.descriptors.serialization.JavaProtoBufUtil
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.storage.LockBasedStorageManager
import java.util.Collections
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache
import org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.jet.lang.resolve.kotlin.AnnotationDescriptorLoader
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.jet.lang.resolve.kotlin.KotlinClassFinder
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe
import org.jetbrains.jet.lang.resolve.kotlin.DescriptorLoadersStorage
import org.jetbrains.jet.lang.resolve.kotlin.ConstantDescriptorLoader
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass
import org.jetbrains.jet.descriptors.serialization.context.DeserializationGlobalContext
import org.jetbrains.jet.lang.PlatformToKotlinClassMap
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.descriptors.serialization.ClassData
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl
public fun DeserializerForDecompiler(classFile: VirtualFile): DeserializerForDecompiler {
val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile)
assert(kotlinClass != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile }
val classFqName = kotlinClass!!.getClassName().getFqNameForClassNameWithoutDollars()
val packageFqName = classFqName.parent()
return DeserializerForDecompiler(classFile.getParent()!!, packageFqName)
}
public class DeserializerForDecompiler(val packageDirectory: VirtualFile, val directoryPackageFqName: FqName) : ResolverForDecompiler {
private val moduleDescriptor =
ModuleDescriptorImpl(Name.special("<module for building decompiled sources>"), listOf(), PlatformToKotlinClassMap.EMPTY)
private fun createDummyModule(name: String) = ModuleDescriptorImpl(Name.special("<$name>"), listOf(), PlatformToKotlinClassMap.EMPTY)
override fun resolveTopLevelClass(classFqName: FqName) = deserializationContext.classDeserializer.deserializeClass(classFqName.toClassId())
override fun resolveDeclarationsInPackage(packageFqName: FqName): Collection<DeclarationDescriptor> {
assert(packageFqName == directoryPackageFqName, "Was called for $packageFqName but only $directoryPackageFqName is expected.")
val packageClassFqName = PackageClassUtils.getPackageClassFqName(packageFqName)
val binaryClassForPackageClass = localClassFinder.findKotlinClass(packageClassFqName)
val annotationData = binaryClassForPackageClass?.getClassHeader()?.annotationData
if (annotationData == null) {
LOG.error("Could not read annotation data for $packageFqName from ${binaryClassForPackageClass?.getClassName()}")
return Collections.emptyList()
}
val membersScope = DeserializedPackageMemberScope(
createDummyPackageFragment(packageFqName),
JavaProtoBufUtil.readPackageDataFrom(annotationData),
deserializationContext
) { listOf() }
return membersScope.getAllDescriptors()
}
private val localClassFinder = object: KotlinClassFinder {
override fun findKotlinClass(fqName: FqName) = findKotlinClass(fqName.toClassId())
override fun findKotlinClass(javaClass: JavaClass) = findKotlinClass(javaClass.getFqName()!!)
fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? {
if (classId.getPackageFqName() != directoryPackageFqName) {
return null
}
val segments = DeserializedResolverUtils.kotlinFqNameToJavaFqName(classId.getRelativeClassName()).pathSegments()
val targetName = segments.makeString("$", postfix = ".class")
val virtualFile = packageDirectory.findChild(targetName)
if (virtualFile != null && isKotlinCompiledFile(virtualFile)) {
return KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile)
}
return null
}
}
private val storageManager = LockBasedStorageManager.NO_LOCKS
private val loadersStorage = DescriptorLoadersStorage(storageManager);
{
loadersStorage.setModule(moduleDescriptor)
loadersStorage.setErrorReporter(LOGGING_REPORTER)
}
private val annotationLoader = AnnotationDescriptorLoader();
{
annotationLoader.setModule(moduleDescriptor)
annotationLoader.setKotlinClassFinder(localClassFinder)
annotationLoader.setErrorReporter(LOGGING_REPORTER)
annotationLoader.setStorage(loadersStorage)
}
private val constantLoader = ConstantDescriptorLoader();
{
constantLoader.setKotlinClassFinder(localClassFinder)
constantLoader.setErrorReporter(LOGGING_REPORTER)
constantLoader.setStorage(loadersStorage)
}
private val classDataFinder = object : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassData? {
val binaryClass = localClassFinder.findKotlinClass(classId) ?: return null
val data = binaryClass.getClassHeader().annotationData
if (data == null) {
LOG.error("Annotation data missing for ${binaryClass.getClassName()}")
return null
}
return JavaProtoBufUtil.readClassDataFrom(data)
}
}
private val packageFragmentProvider = object : PackageFragmentProvider {
override fun getPackageFragments(fqName: FqName): List<PackageFragmentDescriptor> {
return listOf(createDummyPackageFragment(fqName))
}
override fun getSubPackagesOf(fqName: FqName): Collection<FqName> {
throw UnsupportedOperationException("This method is not supposed to be called.")
}
}
{
moduleDescriptor.initialize(packageFragmentProvider)
moduleDescriptor.addDependencyOnModule(moduleDescriptor)
moduleDescriptor.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule())
val moduleContainingMissingDependencies = createDummyModule("module containing missing dependencies for decompiled sources")
moduleContainingMissingDependencies.addDependencyOnModule(moduleContainingMissingDependencies)
moduleContainingMissingDependencies.initialize(
PackageFragmentProviderForMissingDependencies(moduleContainingMissingDependencies)
)
moduleDescriptor.addDependencyOnModule(moduleContainingMissingDependencies)
moduleDescriptor.seal()
moduleContainingMissingDependencies.seal()
}
val deserializationContext = DeserializationGlobalContext(storageManager, moduleDescriptor, classDataFinder, annotationLoader,
constantLoader, packageFragmentProvider)
private fun createDummyPackageFragment(fqName: FqName): MutablePackageFragmentDescriptor {
return MutablePackageFragmentDescriptor(moduleDescriptor, fqName)
}
// we need a "magic" way to obtain ClassId from FqName
// the idea behind this function is that we need accurate class ids only for "neighbouring" classes (inner classes, class object, etc)
// for all others we can build any ClassId since it will resolve to MissingDependencyErrorClassDescriptor which only stores fqName
private fun FqName.toClassId(): ClassId {
val segments = pathSegments()
val packageSegmentsCount = directoryPackageFqName.pathSegments().size
if (segments.size <= packageSegmentsCount) {
return ClassId.topLevel(this)
}
val packageFqName = FqName.fromSegments(segments.subList(0, packageSegmentsCount) map { it.asString() })
if (packageFqName == directoryPackageFqName) {
return ClassId(packageFqName, FqNameUnsafe.fromSegments(segments.subList(packageSegmentsCount, segments.size)))
}
return ClassId.topLevel(this)
}
class object {
private val LOG = Logger.getInstance(javaClass<DeserializerForDecompiler>())
private object LOGGING_REPORTER: ErrorReporter {
override fun reportLoadingError(message: String, exception: Exception?) {
LOG.error(message, exception)
}
override fun reportCannotInferVisibility(descriptor: CallableMemberDescriptor) {
LOG.error("Could not infer visibility for $descriptor")
}
override fun reportIncompatibleAbiVersion(kotlinClass: KotlinJvmBinaryClass, actualVersion: Int) {
LOG.error("Incompatible ABI version for class ${kotlinClass.getClassName()}, actual version: $actualVersion")
}
}
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiManager;
import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.compiled.ClsStubBuilder;
import org.jetbrains.annotations.NotNull;
public class JetClassFileDecompiler extends ClassFileDecompilers.Full {
private final ClsStubBuilder stubBuilder = new JetClsStubBuilder();
@Override
public boolean accepts(@NotNull VirtualFile file) {
return LibrariesPackage.isKotlinCompiledFile(file);
}
@NotNull
@Override
public ClsStubBuilder getStubBuilder() {
return stubBuilder;
}
@NotNull
@Override
public FileViewProvider createFileViewProvider(@NotNull VirtualFile file, @NotNull PsiManager manager, boolean physical) {
return new JetClassFileViewProvider(manager, file, physical, LibrariesPackage.isKotlinInternalCompiledFile(file));
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.SingleRootFileViewProvider
import org.jetbrains.jet.plugin.JetLanguage
import kotlin.properties.Delegates
public class JetClassFileViewProvider(
manager: PsiManager,
file: VirtualFile,
physical: Boolean,
val isInternal: Boolean
) : SingleRootFileViewProvider(manager, file, physical, JetLanguage.INSTANCE) {
val decompiledText by Delegates.blockingLazy(this) {
buildDecompiledText(getVirtualFile())
}
override fun getContents(): CharSequence {
return if (isInternal) "" else decompiledText.text
}
override fun createFile(project: Project, file: VirtualFile, fileType: FileType): PsiFile? {
//TODO: check index that file is library file, as in ClassFileViewProvider
if (isInternal) return null
return JetClsFile(this)
}
override fun createCopy(copy: VirtualFile): SingleRootFileViewProvider {
return JetClassFileViewProvider(getManager(), copy, false, isInternal)
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import com.intellij.openapi.util.TextRange
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.annotations.TestOnly
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.psi.JetDeclaration
import kotlin.properties.Delegates
public class JetClsFile(val provider: JetClassFileViewProvider) : ClsFileImpl(provider) {
private val decompiledFile by Delegates.blockingLazy(this) {
JetDummyClassFileViewProvider.createJetFile(provider.getManager(), getVirtualFile(), provider.decompiledText.text)
}
override fun getDecompiledPsiFile() = decompiledFile
public fun getDeclarationForDescriptor(descriptor: DeclarationDescriptor): JetDeclaration? {
val key = descriptorToKey(descriptor)
val range = provider.decompiledText.renderedDescriptorsToRange[key]
if (range == null) {
return null
}
return PsiTreeUtil.findElementOfClassAtRange(decompiledFile, range.getStartOffset(), range.getEndOffset(), javaClass<JetDeclaration>())
}
TestOnly
fun getRenderedDescriptorsToRange(): Map<String, TextRange> {
return provider.decompiledText.renderedDescriptorsToRange
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.compiled.ClsStubBuilder;
import com.intellij.psi.impl.compiled.ClassFileStubBuilder;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.psi.stubs.PsiFileStub;
import com.intellij.util.cls.ClsFormatException;
import com.intellij.util.indexing.FileContent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class JetClsStubBuilder extends ClsStubBuilder {
@Override
public int getStubVersion() {
return ClassFileStubBuilder.STUB_VERSION + 1;
}
@Nullable
@Override
public PsiFileStub<?> buildFileStub(@NotNull FileContent content) throws ClsFormatException {
VirtualFile file = content.getFile();
if (LibrariesPackage.isKotlinInternalCompiledFile(file)) {
return null;
}
return ClsFileImpl.buildFileStub(file, content.getContent());
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import com.intellij.psi.compiled.ClassFileDecompilers
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.impl.compiled.ClsFileImpl
public class JetDecompilerForWrongAbiVersion : ClassFileDecompilers.Light() {
override fun accepts(file: VirtualFile) = isKotlinCompiledFileWithIncompatibleAbiVersion(file)
override fun getText(file: VirtualFile) = "$INCOMPATIBLE_ABI_VERSION_COMMENT\n${ClsFileImpl.decompile(file)}"
}
val INCOMPATIBLE_ABI_VERSION_COMMENT = " // This Kotlin file has an incompatible ABI version and is displayed as Java class"
@@ -0,0 +1,193 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.SharedPsiElementImplUtil;
import com.intellij.psi.impl.source.tree.LeafElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.JetLanguage;
import java.util.Collections;
import java.util.List;
import java.util.Set;
class JetDummyClassFileViewProvider extends UserDataHolderBase implements FileViewProvider {
private final String text;
private final PsiManager manager;
private JetFile jetFile = null;
private final VirtualFile virtualFile;
public JetDummyClassFileViewProvider(@NotNull PsiManager manager, @NotNull VirtualFile file, String text) {
this.manager = manager;
virtualFile = file;
this.text = text;
jetFile = new JetFile(this, true) {
@Override
public VirtualFile getVirtualFile() {
return virtualFile; // overridden to return not-null; original method returns null when isEventSystemEnabled() = false
}
};
}
@Override
@NotNull
public PsiManager getManager() {
return manager;
}
@Override
@Nullable
public Document getDocument() {
return null;
}
@Override
@NotNull
public String getContents() {
return text;
}
@Override
@NotNull
public VirtualFile getVirtualFile() {
return virtualFile;
}
@Override
@NotNull
public Language getBaseLanguage() {
return JetLanguage.INSTANCE;
}
@Override
@NotNull
public Set<Language> getLanguages() {
return Collections.singleton(getBaseLanguage());
}
@Override
public JetFile getPsi(@NotNull Language target) {
if (JetLanguage.INSTANCE != target) {
return null;
}
return jetFile;
}
@Override
@NotNull
public List<PsiFile> getAllFiles() {
return Collections.<PsiFile>singletonList(jetFile);
}
@Override
public void beforeContentsSynchronized() {
}
@Override
public void contentsSynchronized() {
}
@Override
public boolean isEventSystemEnabled() {
return false;
}
@Override
public boolean isPhysical() {
return false;
}
@Override
public long getModificationStamp() {
return 0;
}
@Override
public boolean supportsIncrementalReparse(@NotNull Language rootLanguage) {
return true;
}
@Override
public void rootChanged(@NotNull PsiFile psiFile) {
}
@Override
public FileViewProvider clone(){
throw new UnsupportedOperationException();
}
@Override
public PsiReference findReferenceAt(int offset) {
return SharedPsiElementImplUtil.findReferenceAt(getPsi(getBaseLanguage()), offset);
}
@Override
@Nullable
public PsiElement findElementAt(int offset, @NotNull Language language) {
return language == getBaseLanguage() ? findElementAt(offset) : null;
}
@Override
public PsiElement findElementAt(int offset, @NotNull Class<? extends Language> lang) {
if (JetLanguage.class != lang) {
return null;
}
return findElementAt(offset);
}
@Override
public PsiElement findElementAt(int offset) {
LeafElement element = jetFile.calcTreeElement().findLeafElementAt(offset);
return element != null ? element.getPsi() : null;
}
@Override
public PsiReference findReferenceAt(int offsetInElement, @NotNull Language language) {
if (JetLanguage.INSTANCE != language) {
return null;
}
return findReferenceAt(offsetInElement);
}
@NotNull
@Override
public FileViewProvider createCopy(@NotNull VirtualFile copy) {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public PsiFile getStubBindingRoot() {
PsiFile psi = getPsi(getBaseLanguage());
assert psi != null;
return psi;
}
@NotNull
public static JetFile createJetFile(PsiManager psiManager, VirtualFile file, String text) {
return new JetDummyClassFileViewProvider(psiManager, file, text).getPsi(JetLanguage.INSTANCE);
}
}
@@ -0,0 +1,491 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.jet.context.ContextPackage;
import org.jetbrains.jet.context.GlobalContextImpl;
import org.jetbrains.jet.di.InjectorForLazyResolve;
import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.mapping.KotlinToJavaTypesMap;
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.plugin.libraries.MemberMatching.*;
public class JetSourceNavigationHelper {
private static boolean forceResolve = false;
private JetSourceNavigationHelper() {
}
@Nullable
public static JetClassOrObject getSourceClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
if (decompiledClassOrObject instanceof JetObjectDeclaration && decompiledClassOrObject.getParent() instanceof JetClassObject) {
// class object case
JetClass decompiledClass = PsiTreeUtil.getParentOfType(decompiledClassOrObject, JetClass.class);
assert decompiledClass != null;
JetClass sourceClass = (JetClass) getSourceForNamedClassOrObject(decompiledClass);
if (sourceClass == null) {
return null;
}
if (sourceClass.hasModifier(JetTokens.ENUM_KEYWORD)) {
return sourceClass;
}
JetClassObject classObject = sourceClass.getClassObject();
assert classObject != null;
return classObject.getObjectDeclaration();
}
return getSourceForNamedClassOrObject(decompiledClassOrObject);
}
@NotNull
private static GlobalSearchScope createLibrarySourcesScope(@NotNull JetNamedDeclaration decompiledDeclaration) {
JetFile containingFile = decompiledDeclaration.getContainingJetFile();
VirtualFile libraryFile = containingFile.getVirtualFile();
if (libraryFile == null) {
return GlobalSearchScope.EMPTY_SCOPE;
}
Project project = decompiledDeclaration.getProject();
ProjectFileIndex projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
if (!projectFileIndex.isInLibraryClasses(libraryFile)) {
return GlobalSearchScope.EMPTY_SCOPE;
}
Set<VirtualFile> sourceRootSet = Sets.newLinkedHashSet();
for (OrderEntry entry : projectFileIndex.getOrderEntriesForFile(libraryFile)) {
if (entry instanceof LibraryOrSdkOrderEntry) {
KotlinPackage.addAll(sourceRootSet, entry.getFiles(OrderRootType.SOURCES));
}
}
return new LibrarySourcesScope(project, sourceRootSet);
}
private static List<JetFile> getContainingFiles(@NotNull Iterable<JetNamedDeclaration> declarations) {
Set<JetFile> result = Sets.newHashSet();
for (JetNamedDeclaration declaration : declarations) {
PsiFile containingFile = declaration.getContainingFile();
if (containingFile instanceof JetFile) {
result.add((JetFile) containingFile);
}
}
return Lists.newArrayList(result);
}
private static boolean haveRenamesInImports(@NotNull List<JetFile> files) {
for (JetFile file : files) {
for (JetImportDirective importDirective : file.getImportDirectives()) {
if (importDirective.getAliasName() != null) {
return true;
}
}
}
return false;
}
@Nullable
private static JetNamedDeclaration findSpecialProperty(@NotNull Name memberName, @NotNull JetClass containingClass) {
// property constructor parameters
List<JetParameter> constructorParameters = containingClass.getPrimaryConstructorParameters();
for (JetParameter constructorParameter : constructorParameters) {
if (memberName.equals(constructorParameter.getNameAsName()) && constructorParameter.hasValOrVarNode()) {
return constructorParameter;
}
}
// enum entries
if (containingClass.hasModifier(JetTokens.ENUM_KEYWORD)) {
for (JetEnumEntry enumEntry : ContainerUtil.findAll(containingClass.getDeclarations(), JetEnumEntry.class)) {
if (memberName.equals(enumEntry.getNameAsName())) {
return enumEntry;
}
}
}
return null;
}
@Nullable
private static JetNamedDeclaration getSourcePropertyOrFunction(@NotNull JetNamedDeclaration decompiledDeclaration) {
String memberNameAsString = decompiledDeclaration.getName();
assert memberNameAsString != null;
Name memberName = Name.identifier(memberNameAsString);
PsiElement decompiledContainer = decompiledDeclaration.getParent();
Collection<JetNamedDeclaration> candidates;
if (decompiledContainer instanceof JetFile) {
candidates = getInitialTopLevelCandidates(decompiledDeclaration);
}
else if (decompiledContainer instanceof JetClassBody) {
JetClassOrObject decompiledClassOrObject = (JetClassOrObject) decompiledContainer.getParent();
JetClassOrObject sourceClassOrObject = getSourceClassOrObject(decompiledClassOrObject);
//noinspection unchecked
candidates = sourceClassOrObject == null
? Collections.<JetNamedDeclaration>emptyList()
: getInitialMemberCandidates(sourceClassOrObject, memberName, (Class<JetNamedDeclaration>) decompiledDeclaration.getClass());
if (candidates.isEmpty()) {
if (decompiledDeclaration instanceof JetProperty && sourceClassOrObject instanceof JetClass) {
return findSpecialProperty(memberName, (JetClass) sourceClassOrObject);
}
}
}
else {
throw new IllegalStateException("Unexpected container of decompiled declaration: "
+ decompiledContainer.getClass().getSimpleName());
}
if (!forceResolve) {
candidates = filterByReceiverPresenceAndParametersCount(decompiledDeclaration, candidates);
if (candidates.size() <= 1) {
return candidates.isEmpty() ? null : candidates.iterator().next();
}
if (!haveRenamesInImports(getContainingFiles(candidates))) {
candidates = filterByReceiverAndParameterTypes(decompiledDeclaration, candidates);
if (candidates.size() <= 1) {
return candidates.isEmpty() ? null : candidates.iterator().next();
}
}
}
KotlinCodeAnalyzer analyzer = createAnalyzer(candidates, decompiledDeclaration.getProject());
for (JetNamedDeclaration candidate : candidates) {
//noinspection unchecked
CallableDescriptor candidateDescriptor = (CallableDescriptor) analyzer.resolveToDescriptor(candidate);
if (receiversMatch(decompiledDeclaration, candidateDescriptor)
&& valueParametersTypesMatch(decompiledDeclaration, candidateDescriptor)
&& typeParametersMatch((JetTypeParameterListOwner) decompiledDeclaration, candidateDescriptor.getTypeParameters())) {
return candidate;
}
}
return null;
}
@NotNull
private static KotlinCodeAnalyzer createAnalyzer(
@NotNull Collection<JetNamedDeclaration> candidates,
@NotNull Project project
) {
GlobalContextImpl globalContext = ContextPackage.GlobalContext();
FileBasedDeclarationProviderFactory providerFactory = new FileBasedDeclarationProviderFactory(
globalContext.getStorageManager(),
getContainingFiles(candidates)
);
ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(Name.special("<library module>"),
AnalyzerFacadeForJVM.DEFAULT_IMPORTS,
PlatformToKotlinClassMap.EMPTY);
moduleDescriptor.addDependencyOnModule(moduleDescriptor);
moduleDescriptor.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
moduleDescriptor.seal();
ResolveSession resolveSession = new InjectorForLazyResolve(
project,
globalContext,
moduleDescriptor,
providerFactory,
new BindingTraceContext()).getResolveSession();
moduleDescriptor.initialize(resolveSession.getPackageFragmentProvider());
return resolveSession;
}
@Nullable
private static JetClassOrObject getSourceForNamedClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
FqName classFqName = decompiledClassOrObject.getFqName();
assert classFqName != null;
GlobalSearchScope librarySourcesScope = createLibrarySourcesScope(decompiledClassOrObject);
if (librarySourcesScope == GlobalSearchScope.EMPTY_SCOPE) { // .getProject() == null for EMPTY_SCOPE, and this breaks code
return null;
}
Collection<JetClassOrObject> classes = JetFullClassNameIndex.getInstance()
.get(classFqName.asString(), decompiledClassOrObject.getProject(), librarySourcesScope);
if (classes.isEmpty()) {
return null;
}
return classes.iterator().next(); // if there are more than one class with this FQ, find first of them
}
@NotNull
private static Collection<JetNamedDeclaration> getInitialTopLevelCandidates(@NotNull JetNamedDeclaration decompiledDeclaration) {
FqName memberFqName = decompiledDeclaration.getFqName();
assert memberFqName != null;
GlobalSearchScope librarySourcesScope = createLibrarySourcesScope(decompiledDeclaration);
if (librarySourcesScope == GlobalSearchScope.EMPTY_SCOPE) { // .getProject() == null for EMPTY_SCOPE, and this breaks code
return Collections.emptyList();
}
//noinspection unchecked
StringStubIndexExtension<JetNamedDeclaration> index =
(StringStubIndexExtension<JetNamedDeclaration>) getIndexForTopLevelPropertyOrFunction(decompiledDeclaration);
return index.get(memberFqName.asString(), decompiledDeclaration.getProject(), librarySourcesScope);
}
private static StringStubIndexExtension<? extends JetNamedDeclaration> getIndexForTopLevelPropertyOrFunction(
@NotNull JetNamedDeclaration decompiledDeclaration
) {
if (decompiledDeclaration instanceof JetNamedFunction) {
return JetTopLevelFunctionsFqnNameIndex.getInstance();
}
if (decompiledDeclaration instanceof JetProperty) {
return JetTopLevelPropertiesFqnNameIndex.getInstance();
}
throw new IllegalArgumentException("Neither function nor declaration: " + decompiledDeclaration.getClass().getName());
}
@NotNull
private static List<JetNamedDeclaration> getInitialMemberCandidates(
@NotNull JetClassOrObject sourceClassOrObject,
@NotNull final Name name,
@NotNull Class<JetNamedDeclaration> declarationClass
) {
List<JetNamedDeclaration> allByClass = ContainerUtil.findAll(sourceClassOrObject.getDeclarations(), declarationClass);
return ContainerUtil.filter(allByClass, new Condition<JetNamedDeclaration>() {
@Override
public boolean value(JetNamedDeclaration declaration) {
return name.equals(declaration.getNameAsSafeName());
}
});
}
@NotNull
private static List<JetNamedDeclaration> filterByReceiverPresenceAndParametersCount(
final @NotNull JetNamedDeclaration decompiledDeclaration,
@NotNull Collection<JetNamedDeclaration> candidates
) {
return ContainerUtil.filter(candidates, new Condition<JetNamedDeclaration>() {
@Override
public boolean value(JetNamedDeclaration candidate) {
return sameReceiverPresenceAndParametersCount(candidate, decompiledDeclaration);
}
});
}
@NotNull
private static List<JetNamedDeclaration> filterByReceiverAndParameterTypes(
final @NotNull JetNamedDeclaration decompiledDeclaration,
@NotNull Collection<JetNamedDeclaration> candidates
) {
return ContainerUtil.filter(candidates, new Condition<JetNamedDeclaration>() {
@Override
public boolean value(JetNamedDeclaration candidate) {
return receiverAndParametersShortTypesMatch(candidate, decompiledDeclaration);
}
});
}
@Nullable
public static JetNamedDeclaration getSourceProperty(@NotNull JetProperty decompiledProperty) {
return getSourcePropertyOrFunction(decompiledProperty);
}
@Nullable
public static JetNamedDeclaration getSourceFunction(@NotNull JetNamedFunction decompiledFunction) {
return getSourcePropertyOrFunction(decompiledFunction);
}
@TestOnly
static void setForceResolve(boolean forceResolve) {
JetSourceNavigationHelper.forceResolve = forceResolve;
}
@Nullable
public static PsiClass getOriginalPsiClassOrCreateLightClass(@NotNull JetClassOrObject classOrObject) {
if (LightClassUtil.belongsToKotlinBuiltIns(classOrObject.getContainingJetFile())) {
Name className = classOrObject.getNameAsName();
assert className != null : "Class from BuiltIns should have a name";
ClassDescriptor classDescriptor = KotlinBuiltIns.getInstance().getBuiltInClassByName(className);
FqNameUnsafe fqName = DescriptorUtils.getFqName(classDescriptor);
if (fqName.isSafe()) {
FqName javaFqName = KotlinToJavaTypesMap.getInstance().getKotlinToJavaFqName(fqName.toSafe());
if (javaFqName != null) {
return JavaPsiFacade.getInstance(classOrObject.getProject()).findClass(
javaFqName.asString(), GlobalSearchScope.allScope(classOrObject.getProject()));
}
}
}
return LightClassUtil.getPsiClass(classOrObject);
}
@Nullable
public static PsiClass getOriginalClass(@NotNull JetClassOrObject classOrObject) {
// Copied from JavaPsiImplementationHelperImpl:getOriginalClass()
String internalName = PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
if (internalName == null) {
return null;
}
String fqName = JvmClassName.byInternalName(internalName).getFqNameForClassNameWithoutDollars().asString();
JetFile file = classOrObject.getContainingJetFile();
VirtualFile vFile = file.getVirtualFile();
Project project = file.getProject();
final ProjectFileIndex idx = ProjectRootManager.getInstance(project).getFileIndex();
if (vFile == null || !idx.isInLibrarySource(vFile)) return null;
final Set<OrderEntry> orderEntries = new THashSet<OrderEntry>(idx.getOrderEntriesForFile(vFile));
return JavaPsiFacade.getInstance(project).findClass(fqName, new GlobalSearchScope(project) {
@Override
public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
return 0;
}
@Override
public boolean contains(@NotNull VirtualFile file) {
List<OrderEntry> entries = idx.getOrderEntriesForFile(file);
for (OrderEntry entry : entries) {
if (orderEntries.contains(entry)) return true;
}
return false;
}
@Override
public boolean isSearchInModuleContent(@NotNull Module aModule) {
return false;
}
@Override
public boolean isSearchInLibraries() {
return true;
}
});
}
@NotNull
public static JetDeclaration replaceBySourceDeclarationIfPresent(@NotNull JetDeclaration original) {
JetDeclaration sourceElement = original.accept(new SourceForDecompiledExtractingVisitor(), null);
return sourceElement != null ? sourceElement : original;
}
private static class SourceForDecompiledExtractingVisitor extends JetVisitor<JetDeclaration, Void> {
@Override
public JetDeclaration visitNamedFunction(@NotNull JetNamedFunction function, Void data) {
return getSourceFunction(function);
}
@Override
public JetDeclaration visitProperty(@NotNull JetProperty property, Void data) {
return getSourceProperty(property);
}
@Override
public JetDeclaration visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, Void data) {
return getSourceClassOrObject(declaration);
}
@Override
public JetDeclaration visitClass(@NotNull JetClass klass, Void data) {
return getSourceClassOrObject(klass);
}
}
private static class LibrarySourcesScope extends GlobalSearchScope {
private final Set<VirtualFile> sources;
private final ProjectFileIndex fileIndex;
public LibrarySourcesScope(Project project, Set<VirtualFile> sources) {
super(project);
fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
this.sources = sources;
}
@Override
public boolean contains(@NotNull VirtualFile file) {
if (fileIndex.isInLibrarySource(file)) {
return sources.contains(fileIndex.getSourceRootForFile(file));
}
return false;
}
@Override
public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
return 0;
}
@Override
public boolean isSearchInModuleContent(@NotNull Module aModule) {
return false;
}
@Override
public boolean isSearchInLibraries() {
return true;
}
}
}
@@ -0,0 +1,246 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class MemberMatching {
/* DECLARATIONS ROUGH MATCHING */
@Nullable
private static JetTypeReference getReceiverType(@NotNull JetNamedDeclaration propertyOrFunction) {
if (propertyOrFunction instanceof JetNamedFunction) {
return ((JetNamedFunction) propertyOrFunction).getReceiverTypeRef();
}
if (propertyOrFunction instanceof JetProperty) {
return ((JetProperty) propertyOrFunction).getReceiverTypeRef();
}
throw new IllegalArgumentException("Neither function nor declaration: " + propertyOrFunction.getClass().getName());
}
@NotNull
private static List<JetParameter> getValueParameters(@NotNull JetNamedDeclaration propertyOrFunction) {
if (propertyOrFunction instanceof JetNamedFunction) {
return ((JetNamedFunction) propertyOrFunction).getValueParameters();
}
if (propertyOrFunction instanceof JetProperty) {
return Collections.emptyList();
}
throw new IllegalArgumentException("Neither function nor declaration: " + propertyOrFunction.getClass().getName());
}
private static String getTypeShortName(@NotNull JetTypeReference typeReference) {
JetTypeElement typeElement = typeReference.getTypeElement();
assert typeElement != null;
return typeElement.accept(new JetVisitor<String, Void>() {
@Override
public String visitDeclaration(@NotNull JetDeclaration declaration, Void data) {
throw new IllegalStateException("This visitor shouldn't be invoked for " + declaration.getClass());
}
@Override
public String visitUserType(@NotNull JetUserType type, Void data) {
JetSimpleNameExpression referenceExpression = type.getReferenceExpression();
assert referenceExpression != null;
return referenceExpression.getReferencedName();
}
@Override
public String visitFunctionType(@NotNull JetFunctionType type, Void data) {
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
int parameterCount = type.getParameters().size();
if (type.getReceiverTypeRef() == null) {
return builtIns.getFunction(parameterCount).getName().asString();
}
else {
return builtIns.getExtensionFunction(parameterCount).getName().asString();
}
}
@Override
public String visitNullableType(@NotNull JetNullableType nullableType, Void data) {
JetTypeElement innerType = nullableType.getInnerType();
assert innerType != null : "No inner type: " + nullableType;
return innerType.accept(this, null);
}
}, null);
}
private static boolean typesHaveSameShortName(@NotNull JetTypeReference a, @NotNull JetTypeReference b) {
return getTypeShortName(a).equals(getTypeShortName(b));
}
static boolean sameReceiverPresenceAndParametersCount(@NotNull JetNamedDeclaration a, @NotNull JetNamedDeclaration b) {
boolean sameReceiverPresence = (getReceiverType(a) == null) == (getReceiverType(b) == null);
boolean sameParametersCount = getValueParameters(a).size() == getValueParameters(b).size();
return sameReceiverPresence && sameParametersCount;
}
static boolean receiverAndParametersShortTypesMatch(@NotNull JetNamedDeclaration a, @NotNull JetNamedDeclaration b) {
JetTypeReference aReceiver = getReceiverType(a);
JetTypeReference bReceiver = getReceiverType(b);
if ((aReceiver == null) != (bReceiver == null)) {
return false;
}
if (aReceiver != null && !typesHaveSameShortName(aReceiver, bReceiver)) {
return false;
}
List<JetParameter> aParameters = getValueParameters(a);
List<JetParameter> bParameters = getValueParameters(b);
if (aParameters.size() != bParameters.size()) {
return false;
}
for (int i = 0; i < aParameters.size(); i++) {
JetTypeReference aType = aParameters.get(i).getTypeReference();
JetTypeReference bType = bParameters.get(i).getTypeReference();
assert aType != null;
assert bType != null;
if (!typesHaveSameShortName(aType, bType)) {
return false;
}
}
return true;
}
/* DECLARATION AND DESCRIPTOR STRICT MATCHING */
static boolean receiversMatch(@NotNull JetNamedDeclaration declaration, @NotNull CallableDescriptor descriptor) {
JetTypeReference declarationReceiver = getReceiverType(declaration);
ReceiverParameterDescriptor descriptorReceiver = descriptor.getReceiverParameter();
if (declarationReceiver == null && descriptorReceiver == null) {
return true;
}
if (declarationReceiver != null && descriptorReceiver != null) {
return declarationReceiver.getText().equals(DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(descriptorReceiver.getType()));
}
return false;
}
static boolean valueParametersTypesMatch(@NotNull JetNamedDeclaration declaration, @NotNull CallableDescriptor descriptor) {
List<JetParameter> declarationParameters = getValueParameters(declaration);
List<ValueParameterDescriptor> descriptorParameters = descriptor.getValueParameters();
if (descriptorParameters.size() != declarationParameters.size()) {
return false;
}
for (int i = 0; i < descriptorParameters.size(); i++) {
ValueParameterDescriptor descriptorParameter = descriptorParameters.get(i);
JetParameter declarationParameter = declarationParameters.get(i);
JetTypeReference typeReference = declarationParameter.getTypeReference();
if (typeReference == null) {
return false;
}
JetModifierList modifierList = declarationParameter.getModifierList();
boolean varargInDeclaration = modifierList != null && modifierList.hasModifier(JetTokens.VARARG_KEYWORD);
boolean varargInDescriptor = descriptorParameter.getVarargElementType() != null;
if (varargInDeclaration != varargInDescriptor) {
return false;
}
String declarationTypeText = typeReference.getText();
JetType typeToRender = varargInDeclaration ? descriptorParameter.getVarargElementType() : descriptorParameter.getType();
assert typeToRender != null;
String descriptorParameterText = DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(typeToRender);
if (!declarationTypeText.equals(descriptorParameterText)) {
return false;
}
}
return true;
}
static boolean typeParametersMatch(
@NotNull JetTypeParameterListOwner typeParameterListOwner,
@NotNull List<TypeParameterDescriptor> typeParameterDescriptors
) {
List<JetTypeParameter> decompiledParameters = typeParameterListOwner.getTypeParameters();
if (decompiledParameters.size() != typeParameterDescriptors.size()) {
return false;
}
Multimap<Name, String> decompiledParameterToBounds = HashMultimap.create();
for (JetTypeParameter parameter : decompiledParameters) {
JetTypeReference extendsBound = parameter.getExtendsBound();
if (extendsBound != null) {
decompiledParameterToBounds.put(parameter.getNameAsName(), extendsBound.getText());
}
}
for (JetTypeConstraint typeConstraint : typeParameterListOwner.getTypeConstraints()) {
JetSimpleNameExpression typeParameterName = typeConstraint.getSubjectTypeParameterName();
assert typeParameterName != null;
JetTypeReference bound = typeConstraint.getBoundTypeReference();
assert bound != null;
decompiledParameterToBounds.put(typeParameterName.getReferencedNameAsName(), bound.getText());
}
for (int i = 0; i < decompiledParameters.size(); i++) {
JetTypeParameter decompiledParameter = decompiledParameters.get(i);
TypeParameterDescriptor descriptor = typeParameterDescriptors.get(i);
Name name = decompiledParameter.getNameAsName();
assert name != null;
if (!name.equals(descriptor.getName())) {
return false;
}
Set<String> descriptorUpperBounds = Sets.newHashSet(ContainerUtil.map(
descriptor.getUpperBounds(), new Function<JetType, String>() {
@Override
public String fun(JetType type) {
return DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type);
}
}));
Set<String> decompiledUpperBounds = decompiledParameterToBounds.get(descriptor.getName()).isEmpty()
? Sets.newHashSet(DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(KotlinBuiltIns.getInstance().getDefaultBound()))
: Sets.newHashSet(decompiledParameterToBounds.get(descriptor.getName()));
if (!descriptorUpperBounds.equals(decompiledUpperBounds)) {
return false;
}
}
return true;
}
private MemberMatching() {
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
trait ResolverForDecompiler {
fun resolveTopLevelClass(classFqName: FqName): ClassDescriptor?
fun resolveDeclarationsInPackage(packageFqName: FqName): Collection<DeclarationDescriptor>
}
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.libraries
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl
import org.jetbrains.jet.utils.Printer
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.types.error.MissingDependencyErrorClass
import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.jet.lang.types.TypeSubstitutor
import org.jetbrains.jet.lang.types.TypeProjection
import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
import org.jetbrains.jet.lang.types.ErrorUtils.createErrorType
private class PackageFragmentWithMissingDependencies(override val fqName: FqName, moduleDescriptor: ModuleDescriptor) :
PackageFragmentDescriptorImpl(moduleDescriptor, fqName) {
override fun getMemberScope(): JetScope {
return ScopeWithMissingDependencies(fqName, this)
}
}
private class ScopeWithMissingDependencies(val fqName: FqName, val containing: DeclarationDescriptor) : JetScopeImpl() {
override fun getContainingDeclaration(): DeclarationDescriptor {
return containing
}
override fun printScopeStructure(p: Printer) {
p.println("Special scope for decompiler, containing class with any name")
}
override fun getClassifier(name: Name): ClassifierDescriptor? {
return MissingDependencyErrorClassDescriptor(getContainingDeclaration(), fqName.child(name))
}
}
private class PackageFragmentProviderForMissingDependencies(val moduleDescriptor: ModuleDescriptor) : PackageFragmentProvider {
override fun getPackageFragments(fqName: FqName): List<PackageFragmentDescriptor> {
return listOf(PackageFragmentWithMissingDependencies(fqName, moduleDescriptor))
}
override fun getSubPackagesOf(fqName: FqName): Collection<FqName> {
throw UnsupportedOperationException("This method is not supposed to be called.")
}
}
private class MissingDependencyErrorClassDescriptor(containing: DeclarationDescriptor, override val fullFqName: FqName)
: MissingDependencyErrorClass, ClassDescriptorImpl(containing, fullFqName.shortName(), Modality.OPEN, listOf(), SourceElement.NO_SOURCE) {
private val scope = ScopeWithMissingDependencies(fullFqName, this)
override fun substitute(substitutor: TypeSubstitutor): ClassDescriptor {
return this
}
override fun getClassObjectDescriptor(): ClassDescriptor? {
//NOTE: only used in types and rendered fq name should be the same as of containing class
return MissingDependencyErrorClassDescriptor(this, fullFqName)
}
override fun getScopeForMemberLookup(): JetScope {
return scope
}
override fun getMemberScope(typeArguments: List<TypeProjection?>): JetScope {
return scope
}
{
val emptyConstructor = ConstructorDescriptorImpl.create(this, Annotations.EMPTY, true, SourceElement.NO_SOURCE)
emptyConstructor.initialize(listOf(), listOf(), Visibilities.INTERNAL, false)
emptyConstructor.setReturnType(createErrorType("<ERROR RETURN TYPE>"))
initialize(JetScope.EMPTY, setOf(emptyConstructor), emptyConstructor)
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzerFacade;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
public final class AnalyzerFacadeProvider {
private AnalyzerFacadeProvider() {
}
@NotNull
public static AnalyzerFacade getAnalyzerFacadeForFile(@NotNull JetFile file) {
return getAnalyzerFacade(TargetPlatformDetector.getPlatform(file));
}
@NotNull
public static AnalyzerFacade getAnalyzerFacade(@NotNull TargetPlatform targetPlatform) {
return targetPlatform == TargetPlatform.JVM ? AnalyzerFacadeForJVM.INSTANCE : JSAnalyzerFacadeForIDEA.INSTANCE;
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
public final class AnalyzerFacadeWithCache {
private AnalyzerFacadeWithCache() {
}
@NotNull
public static BindingContext getContextForElement(@NotNull JetElement jetElement) {
ResolveSessionForBodies resolveSessionForBodies = ResolvePackage.getLazyResolveSession(jetElement);
return resolveSessionForBodies.resolveToElement(jetElement);
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.config.LibrarySourcesConfig;
public final class IDEAConfig extends LibrarySourcesConfig {
public IDEAConfig(@NotNull Project project) {
super(project, "default", ProjectStructureUtil.getLibLocationForProject(project), EcmaVersion.defaultVersion(), false);
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzerFacade;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
import java.util.Collection;
public enum JSAnalyzerFacadeForIDEA implements AnalyzerFacade {
INSTANCE;
private JSAnalyzerFacadeForIDEA() {
}
@NotNull
@Override
public Setup createSetup(@NotNull Project project, @NotNull Collection<JetFile> syntheticFiles, @NotNull GlobalSearchScope filesScope) {
return new BasicSetup(AnalyzerFacadeForJS.getLazyResolveSession(syntheticFiles, filesScope, new IDEAConfig(project)));
}
}
@@ -0,0 +1,221 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.ProjectRootModificationTracker;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.FileTypeIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.util.PathUtil;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.framework.JsHeaderLibraryDetectionUtil;
import org.jetbrains.jet.plugin.framework.JsLibraryStdDetectionUtil;
import org.jetbrains.jet.plugin.versions.KotlinRuntimeLibraryCoreUtil;
import java.util.*;
public class ProjectStructureUtil {
private static final Key<CachedValue<Boolean>> IS_KOTLIN_JS_MODULE = Key.create("IS_KOTLIN_JS_MODULE");
private static final Key<CachedValue<Boolean>> HAS_KOTLIN_JVM_MODULES = Key.create("HAS_KOTLIN_JVM_MODULES");
private static final Key<CachedValue<Boolean>> IS_DEPEND_ON_JVM_KOTLIN = Key.create("KOTLIN_IS_DEPEND_ON_JVM_KOTLIN");
private ProjectStructureUtil() {
}
public static boolean isJsKotlinModule(@NotNull JetFile file) {
Module module = ModuleUtilCore.findModuleForPsiElement(file);
return module != null && isJsKotlinModule(module);
}
public static boolean isJavaKotlinModule(@NotNull Module module) {
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(
hasKotlinFilesOnlyInTests(module));
return KotlinRuntimeLibraryCoreUtil.getKotlinRuntimeMarkerClass(scope) != null;
}
public static boolean isJsKotlinModule(@NotNull final Module module) {
CachedValue<Boolean> result = module.getUserData(IS_KOTLIN_JS_MODULE);
if (result == null) {
result = CachedValuesManager.getManager(module.getProject()).createCachedValue(new CachedValueProvider<Boolean>() {
@Override
public Result<Boolean> compute() {
return Result.create(getJSStandardLibrary(module) != null, ProjectRootModificationTracker
.getInstance(module.getProject()));
}
}, false);
module.putUserData(IS_KOTLIN_JS_MODULE, result);
}
return result.getValue();
}
public static boolean hasJvmKotlinModules(@NotNull final Project project) {
CachedValue<Boolean> result = project.getUserData(HAS_KOTLIN_JVM_MODULES);
if (result == null) {
result = CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<Boolean>() {
@Override
public Result<Boolean> compute() {
boolean hasJvmKotlinModules = false;
for (Module module : ModuleManager.getInstance(project).getModules()) {
if (isJavaKotlinModule(module)) {
hasJvmKotlinModules = true;
break;
}
}
return Result.create(hasJvmKotlinModules, ProjectRootModificationTracker.getInstance(project));
}
}, false);
project.putUserData(HAS_KOTLIN_JVM_MODULES, result);
}
return result.getValue();
}
public static boolean isUsedInKotlinJavaModule(@NotNull final Module module) {
CachedValue<Boolean> result = module.getUserData(IS_DEPEND_ON_JVM_KOTLIN);
if (result == null) {
result = CachedValuesManager.getManager(module.getProject()).createCachedValue(new CachedValueProvider<Boolean>() {
@Override
public Result<Boolean> compute() {
boolean usedInKotlinModule = false;
Set<Module> dependentModules = new HashSet<Module>();
ModuleUtilCore.collectModulesDependsOn(module, dependentModules);
for (Module module : dependentModules) {
if (isJavaKotlinModule(module)) {
usedInKotlinModule = true;
break;
}
}
return Result.create(usedInKotlinModule, ProjectRootModificationTracker.getInstance(module.getProject()));
}
}, false);
module.putUserData(IS_DEPEND_ON_JVM_KOTLIN, result);
}
return result.getValue();
}
@NotNull
public static List<String> getLibLocationForProject(@NotNull Project project) {
Module[] modules = ModuleManager.getInstance(project).getModules();
for (Module module : modules) {
if (isJsKotlinModule(module)) {
return getLibLocationForProject(module);
}
}
return Collections.emptyList();
}
@NotNull
public static List<String> getLibLocationForProject(@NotNull final Module module) {
final Set<String> pathsToJSLib = Sets.newHashSet();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
ModuleRootManager.getInstance(module).orderEntries().librariesOnly().forEachLibrary(new Processor<Library>() {
@Override
public boolean process(Library library) {
boolean detected = JsHeaderLibraryDetectionUtil.isJsHeaderLibraryDetected(Arrays.asList(
library.getFiles(OrderRootType.CLASSES)));
if (detected) {
for (VirtualFile file : library.getRootProvider().getFiles(OrderRootType.SOURCES)) {
String path = PathUtil.getLocalPath(PathUtil.getLocalFile(file));
if (path != null) {
pathsToJSLib.add(path);
}
else {
assert !file.isValid() : "Path is expected to be null only for invalid file: " + file;
}
}
}
return true;
}
});
}
});
return Lists.newArrayList(pathsToJSLib);
}
@Nullable
private static Library getJSStandardLibrary(final Module module) {
return ApplicationManager.getApplication().runReadAction(new Computable<Library>() {
@Override
public Library compute() {
final Ref<Library> jsLibrary = Ref.create();
ModuleRootManager.getInstance(module).orderEntries().librariesOnly().forEachLibrary(new Processor<Library>() {
@Override
public boolean process(Library library) {
List<VirtualFile> classes = Arrays.asList(library.getFiles(OrderRootType.CLASSES));
boolean detected = JsLibraryStdDetectionUtil.getJsLibraryStdVersion(classes) != null;
if (detected) {
jsLibrary.set(library);
return false;
}
return true;
}
});
return jsLibrary.get();
}
});
}
public static boolean hasKotlinFilesInSources(@NotNull Module module) {
return FileTypeIndex.containsFileOfType(JetFileType.INSTANCE, module.getModuleScope(false));
}
public static boolean hasKotlinFilesOnlyInTests(@NotNull Module module) {
return !hasKotlinFilesInSources(module) && FileTypeIndex.containsFileOfType(JetFileType.INSTANCE, module.getModuleScope(true));
}
}
@@ -0,0 +1,552 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicates;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.*;
import kotlin.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzerPackage;
import org.jetbrains.jet.di.InjectorForBodyResolve;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.lazy.*;
import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.TypeConstructor;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.storage.ExceptionTracker;
import org.jetbrains.jet.storage.LazyResolveStorageManager;
import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
import org.jetbrains.jet.storage.StorageManager;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public class ResolveElementCache {
private final CachedValue<MemoizedFunctionToNotNull<JetElement, BindingContext>> additionalResolveCache;
private final ResolveSession resolveSession;
public ResolveElementCache(ResolveSession resolveSession, Project project) {
this.resolveSession = resolveSession;
// Recreate internal cache after change of modification count
this.additionalResolveCache =
CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<MemoizedFunctionToNotNull<JetElement, BindingContext>>() {
@Nullable
@Override
public Result<MemoizedFunctionToNotNull<JetElement, BindingContext>> compute() {
ResolveSession resolveSession = ResolveElementCache.this.resolveSession;
LazyResolveStorageManager manager = resolveSession.getStorageManager();
MemoizedFunctionToNotNull<JetElement, BindingContext> elementsCacheFunction =
manager.createWeaklyRetainedMemoizedFunction(new Function1<JetElement, BindingContext>() {
@Override
public BindingContext invoke(JetElement jetElement) {
return elementAdditionalResolve(jetElement);
}
});
return Result.create(elementsCacheFunction,
PsiModificationTracker.MODIFICATION_COUNT,
resolveSession.getExceptionTracker());
}
},
false);
}
@NotNull
public BindingContext resolveToElement(@NotNull JetElement jetElement) {
@SuppressWarnings("unchecked") JetElement elementOfAdditionalResolve = (JetElement) JetPsiUtil.getTopmostParentOfTypes(
jetElement,
JetNamedFunction.class,
JetClassInitializer.class,
JetProperty.class,
JetParameter.class,
JetDelegationSpecifierList.class,
JetImportDirective.class,
JetAnnotationEntry.class,
JetTypeParameter.class,
JetTypeConstraint.class,
JetPackageDirective.class,
JetCodeFragment.class);
if (elementOfAdditionalResolve != null && !(elementOfAdditionalResolve instanceof JetParameter)) {
if (elementOfAdditionalResolve instanceof JetPackageDirective) {
elementOfAdditionalResolve = jetElement;
}
return additionalResolveCache.getValue().invoke(elementOfAdditionalResolve);
}
JetParameter parameter = (JetParameter) elementOfAdditionalResolve;
if (parameter != null) {
JetClass klass = PsiTreeUtil.getParentOfType(parameter, JetClass.class);
if (klass != null && parameter.getParent() == klass.getPrimaryConstructorParameterList()) {
return additionalResolveCache.getValue().invoke(klass);
}
// Parameters for function literal could be met inside other parameters. We can't make resolveToDescriptors for internal elements.
jetElement = parameter;
}
JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetElement, JetDeclaration.class, false);
if (declaration != null) {
// Activate descriptor resolution
resolveSession.resolveToDescriptor(declaration);
}
return resolveSession.getBindingContext();
}
@NotNull
private BindingContext elementAdditionalResolve(@NotNull JetElement resolveElement) {
// All additional resolve should be done to separate trace
BindingTrace trace = resolveSession.getStorageManager().createSafeTrace(
new DelegatingBindingTrace(resolveSession.getBindingContext(), "trace to resolve element", resolveElement));
JetFile file = resolveElement.getContainingJetFile();
if (resolveElement instanceof JetNamedFunction) {
functionAdditionalResolve(resolveSession, (JetNamedFunction) resolveElement, trace, file);
}
else if (resolveElement instanceof JetClassInitializer) {
initializerAdditionalResolve(resolveSession, (JetClassInitializer) resolveElement, trace, file);
}
else if (resolveElement instanceof JetProperty) {
propertyAdditionalResolve(resolveSession, (JetProperty) resolveElement, trace, file);
}
else if (resolveElement instanceof JetDelegationSpecifierList) {
delegationSpecifierAdditionalResolve(resolveSession, (JetDelegationSpecifierList) resolveElement, trace, file);
}
else if (resolveElement instanceof JetImportDirective) {
JetImportDirective importDirective = (JetImportDirective) resolveElement;
LazyImportScope scope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(importDirective.getContainingJetFile());
scope.forceResolveAllContents();
}
else if (resolveElement instanceof JetAnnotationEntry) {
annotationAdditionalResolve(resolveSession, (JetAnnotationEntry) resolveElement);
}
else if (resolveElement instanceof JetClass) {
constructorAdditionalResolve(resolveSession, (JetClass) resolveElement, trace, file);
}
else if (resolveElement instanceof JetTypeParameter) {
typeParameterAdditionalResolve(resolveSession, (JetTypeParameter) resolveElement);
}
else if (resolveElement instanceof JetTypeConstraint) {
typeConstraintAdditionalResolve(resolveSession, (JetTypeConstraint) resolveElement);
}
else if (resolveElement instanceof JetCodeFragment) {
codeFragmentAdditionalResolve(resolveSession, (JetCodeFragment) resolveElement, trace);
}
else if (PsiTreeUtil.getParentOfType(resolveElement, JetPackageDirective.class) != null) {
packageRefAdditionalResolve(resolveSession, trace, resolveElement);
}
else {
assert false : "Invalid type of the topmost parent";
}
new JetFlowInformationProvider(resolveElement, trace).checkDeclaration();
return trace.getBindingContext();
}
private static void packageRefAdditionalResolve(ResolveSession resolveSession, BindingTrace trace, JetElement jetElement) {
if (jetElement instanceof JetSimpleNameExpression) {
JetPackageDirective header = PsiTreeUtil.getParentOfType(jetElement, JetPackageDirective.class);
assert header != null;
JetSimpleNameExpression packageNameExpression = (JetSimpleNameExpression) jetElement;
if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, packageNameExpression) == null) {
JetScope scope = getExpressionMemberScope(resolveSession, packageNameExpression);
if (scope != null) {
trace.record(BindingContext.RESOLUTION_SCOPE, packageNameExpression, scope);
}
}
if (Name.isValidIdentifier(packageNameExpression.getReferencedName())) {
if (trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, packageNameExpression) == null) {
FqName fqName = header.getFqName(packageNameExpression);
PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName);
assert packageDescriptor != null: "Package descriptor should be present in session for " + fqName;
trace.record(BindingContext.REFERENCE_TARGET, packageNameExpression, packageDescriptor);
}
}
}
}
private static void typeConstraintAdditionalResolve(KotlinCodeAnalyzer analyzer, JetTypeConstraint jetTypeConstraint) {
JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetTypeConstraint, JetDeclaration.class);
DeclarationDescriptor descriptor = analyzer.resolveToDescriptor(declaration);
assert (descriptor instanceof ClassDescriptor);
TypeConstructor constructor = ((ClassDescriptor) descriptor).getTypeConstructor();
for (TypeParameterDescriptor parameterDescriptor : constructor.getParameters()) {
LazyEntity lazyEntity = (LazyEntity) parameterDescriptor;
lazyEntity.forceResolveAllContents();
}
}
private void codeFragmentAdditionalResolve(
ResolveSession resolveSession,
JetCodeFragment codeFragment,
BindingTrace trace
) {
JetElement codeFragmentExpression = codeFragment.getContentElement();
if (!(codeFragmentExpression instanceof JetExpression)) return;
PsiElement contextElement = codeFragment.getContext();
if (!(contextElement instanceof JetExpression)) return;
JetExpression contextExpression = (JetExpression) contextElement;
BindingContext contextForElement = resolveToElement(contextExpression);
JetScope scopeForContextElement = contextForElement.get(BindingContext.RESOLUTION_SCOPE, contextExpression);
if (scopeForContextElement != null) {
JetScope codeFragmentScope = resolveSession.getScopeProvider().getFileScope(codeFragment);
ChainedScope chainedScope = new ChainedScope(
scopeForContextElement.getContainingDeclaration(),
"Scope for resolve code fragment",
scopeForContextElement,
codeFragmentScope
);
DataFlowInfo dataFlowInfoForContextElement = contextForElement.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, contextExpression);
AnalyzerPackage.computeTypeInContext(
(JetExpression) codeFragmentExpression,
chainedScope,
trace,
dataFlowInfoForContextElement == null ? DataFlowInfo.EMPTY : dataFlowInfoForContextElement,
TypeUtils.NO_EXPECTED_TYPE,
resolveSession.getModuleDescriptor()
);
}
}
private static void annotationAdditionalResolve(ResolveSession resolveSession, JetAnnotationEntry jetAnnotationEntry) {
JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetAnnotationEntry, JetDeclaration.class);
if (declaration != null) {
Annotated descriptor = resolveSession.resolveToDescriptor(declaration);
AnnotationResolver.resolveAnnotationsArguments(
descriptor,
resolveSession.getTrace()
);
ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations());
}
}
private static void typeParameterAdditionalResolve(KotlinCodeAnalyzer analyzer, JetTypeParameter typeParameter) {
DeclarationDescriptor descriptor = analyzer.resolveToDescriptor(typeParameter);
assert descriptor instanceof LazyEntity;
LazyEntity parameterDescriptor = (LazyEntity) descriptor;
parameterDescriptor.forceResolveAllContents();
}
private static void delegationSpecifierAdditionalResolve(
ResolveSession resolveSession,
JetDelegationSpecifierList specifier, BindingTrace trace, JetFile file) {
JetClassOrObject classOrObject = (JetClassOrObject) specifier.getParent();
LazyClassDescriptor descriptor = (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject);
// Activate resolving of supertypes
descriptor.getTypeConstructor().getSupertypes();
BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file);
bodyResolver.resolveDelegationSpecifierList(createEmptyContext(resolveSession), classOrObject, descriptor,
descriptor.getUnsubstitutedPrimaryConstructor(),
descriptor.getScopeForClassHeaderResolution(),
descriptor.getScopeForMemberDeclarationResolution());
}
private static void propertyAdditionalResolve(final ResolveSession resolveSession, final JetProperty jetProperty, BindingTrace trace, JetFile file) {
JetScope propertyResolutionScope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(jetProperty);
BodyResolveContextForLazy bodyResolveContext = new BodyResolveContextForLazy(
createParameters(resolveSession),
new Function<JetDeclaration, JetScope>() {
@Override
public JetScope apply(JetDeclaration declaration) {
assert declaration.getParent() == jetProperty : "Must be called only for property accessors, but called for " +
declaration;
return resolveSession.getScopeProvider().getResolutionScopeForDeclaration(declaration);
}
});
BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file);
PropertyDescriptor descriptor = (PropertyDescriptor) resolveSession.resolveToDescriptor(jetProperty);
JetExpression propertyInitializer = jetProperty.getInitializer();
if (propertyInitializer != null) {
bodyResolver.resolvePropertyInitializer(bodyResolveContext, jetProperty, descriptor, propertyInitializer, propertyResolutionScope);
}
JetExpression propertyDelegate = jetProperty.getDelegateExpression();
if (propertyDelegate != null) {
bodyResolver.resolvePropertyDelegate(bodyResolveContext, jetProperty, descriptor, propertyDelegate, propertyResolutionScope, propertyResolutionScope);
}
bodyResolver.resolvePropertyAccessors(bodyResolveContext, jetProperty, descriptor);
for (JetPropertyAccessor accessor : jetProperty.getAccessors()) {
new JetFlowInformationProvider(accessor, trace).checkDeclaration();
}
}
private static void functionAdditionalResolve(
ResolveSession resolveSession,
JetNamedFunction namedFunction,
BindingTrace trace,
JetFile file
) {
JetScope scope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(namedFunction);
FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction);
BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file);
bodyResolver.resolveFunctionBody(createEmptyContext(resolveSession), trace, namedFunction, functionDescriptor, scope);
}
private static void constructorAdditionalResolve(
ResolveSession resolveSession,
JetClass klass,
BindingTrace trace,
JetFile file
) {
JetScope scope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(klass);
ClassDescriptor classDescriptor = (ClassDescriptor) resolveSession.resolveToDescriptor(klass);
ConstructorDescriptor constructorDescriptor = classDescriptor.getUnsubstitutedPrimaryConstructor();
assert constructorDescriptor != null;
BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file);
bodyResolver.resolveConstructorParameterDefaultValuesAndAnnotations(createEmptyContext(resolveSession), trace, klass,
constructorDescriptor, scope);
}
private static boolean initializerAdditionalResolve(
ResolveSession resolveSession,
JetClassInitializer classInitializer,
BindingTrace trace,
JetFile file
) {
JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(classInitializer, JetClassOrObject.class);
LazyClassDescriptor classOrObjectDescriptor = (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject);
BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file);
bodyResolver.resolveAnonymousInitializer(createEmptyContext(resolveSession), classInitializer, classOrObjectDescriptor);
return true;
}
private static BodyResolver createBodyResolver(ResolveSession resolveSession, BindingTrace trace, JetFile file) {
InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve(
file.getProject(),
createParameters(resolveSession),
trace,
resolveSession.getModuleDescriptor()
);
return bodyResolve.getBodyResolver();
}
private static TopDownAnalysisParameters createParameters(@NotNull ResolveSession resolveSession) {
return TopDownAnalysisParameters.createForLocalDeclarations(
resolveSession.getStorageManager(), resolveSession.getExceptionTracker(),
Predicates.<PsiFile>alwaysTrue());
}
@NotNull
private static BodyResolveContextForLazy createEmptyContext(@NotNull ResolveSession resolveSession) {
return new BodyResolveContextForLazy(createParameters(resolveSession), Functions.<JetScope>constant(null));
}
private static JetScope getExpressionResolutionScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
ScopeProvider provider = resolveSession.getScopeProvider();
JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
if (parentDeclaration == null) {
return provider.getFileScope(expression.getContainingJetFile());
}
return provider.getResolutionScopeForDeclaration(parentDeclaration);
}
private static JetScope getExpressionMemberScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
BindingTrace trace = resolveSession.getStorageManager().createSafeTrace(new DelegatingBindingTrace(
resolveSession.getBindingContext(), "trace to resolve a member scope of expression", expression));
if (BindingContextUtils.isExpressionWithValidReference(expression, resolveSession.getBindingContext())) {
QualifiedExpressionResolver qualifiedExpressionResolver = resolveSession.getQualifiedExpressionResolver();
// In some type declaration
if (expression.getParent() instanceof JetUserType) {
JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier();
if (qualifier != null) {
Collection<? extends DeclarationDescriptor> descriptors = qualifiedExpressionResolver
.lookupDescriptorsForUserType(qualifier, getExpressionResolutionScope(resolveSession, expression), trace);
for (DeclarationDescriptor descriptor : descriptors) {
if (descriptor instanceof LazyPackageDescriptor) {
return ((LazyPackageDescriptor) descriptor).getMemberScope();
}
}
}
}
// Inside import
if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class, false) != null) {
PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT);
assert rootPackage != null;
if (expression.getParent() instanceof JetDotQualifiedExpression) {
JetExpression element = ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression();
FqName fqName = expression.getContainingJetFile().getPackageFqName();
PackageViewDescriptor filePackage = resolveSession.getModuleDescriptor().getPackage(fqName);
assert filePackage != null : "File package should be already resolved and be found";
JetScope scope = filePackage.getMemberScope();
Collection<? extends DeclarationDescriptor> descriptors;
if (element instanceof JetDotQualifiedExpression) {
descriptors = qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression(
(JetDotQualifiedExpression) element, rootPackage.getMemberScope(), scope, trace,
QualifiedExpressionResolver.LookupMode.EVERYTHING, false);
}
else {
descriptors = qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference(
(JetSimpleNameExpression) element, rootPackage.getMemberScope(), scope, trace,
QualifiedExpressionResolver.LookupMode.EVERYTHING, false, false);
}
for (DeclarationDescriptor descriptor : descriptors) {
if (descriptor instanceof PackageViewDescriptor) {
return ((PackageViewDescriptor) descriptor).getMemberScope();
}
}
}
else {
return rootPackage.getMemberScope();
}
}
// Inside package declaration
JetPackageDirective packageDirective = PsiTreeUtil.getParentOfType(expression, JetPackageDirective.class, false);
if (packageDirective != null) {
PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(
packageDirective.getFqName((JetSimpleNameExpression) expression).parent());
if (packageDescriptor != null) {
return packageDescriptor.getMemberScope();
}
}
}
return null;
}
private static class BodyResolveContextForLazy implements BodiesResolveContext {
private final Function<? super JetDeclaration, JetScope> declaringScopes;
private final TopDownAnalysisParameters topDownAnalysisParameters;
private BodyResolveContextForLazy(
@NotNull TopDownAnalysisParameters parameters,
@NotNull Function<? super JetDeclaration, JetScope> declaringScopes
) {
this.topDownAnalysisParameters = parameters;
this.declaringScopes = declaringScopes;
}
@NotNull
@Override
public StorageManager getStorageManager() {
return topDownAnalysisParameters.getStorageManager();
}
@NotNull
@Override
public ExceptionTracker getExceptionTracker() {
return topDownAnalysisParameters.getExceptionTracker();
}
@Override
public Collection<JetFile> getFiles() {
return Collections.emptySet();
}
@Override
public Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> getDeclaredClasses() {
return Collections.emptyMap();
}
@Override
public Map<JetClassInitializer, ClassDescriptorWithResolutionScopes> getAnonymousInitializers() {
return Collections.emptyMap();
}
@Override
public Map<JetProperty, PropertyDescriptor> getProperties() {
return Collections.emptyMap();
}
@Override
public Map<JetNamedFunction, SimpleFunctionDescriptor> getFunctions() {
return Collections.emptyMap();
}
@Override
public Function<JetDeclaration, JetScope> getDeclaringScopes() {
//noinspection unchecked
return (Function<JetDeclaration, JetScope>) declaringScopes;
}
@Override
public Map<JetScript, ScriptDescriptor> getScripts() {
return Collections.emptyMap();
}
@Override
public DataFlowInfo getOuterDataFlowInfo() {
return DataFlowInfo.EMPTY;
}
@NotNull
@Override
public TopDownAnalysisParameters getTopDownAnalysisParameters() {
return topDownAnalysisParameters;
}
@Override
public boolean completeAnalysisNeeded(@NotNull PsiElement element) {
return true;
}
}
}
@@ -0,0 +1,141 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ModificationTracker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider;
import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.storage.ExceptionTracker;
import org.jetbrains.jet.storage.StorageManager;
import java.util.Collection;
public class ResolveSessionForBodies implements KotlinCodeAnalyzer, ModificationTracker {
private final Object createdForObject;
private final ResolveSession resolveSession;
private final ResolveElementCache resolveElementCache;
public ResolveSessionForBodies(@NotNull Project project, @NotNull ResolveSession resolveSession) {
this(project, project, resolveSession);
}
private ResolveSessionForBodies(Object createdForObject, Project project, ResolveSession resolveSession) {
this.createdForObject = createdForObject;
this.resolveSession = resolveSession;
this.resolveElementCache = new ResolveElementCache(resolveSession, project);
}
@NotNull
public BindingContext resolveToElement(JetElement element) {
return resolveElementCache.resolveToElement(element);
}
@NotNull
@Override
public ModuleDescriptor getModuleDescriptor() {
return resolveSession.getModuleDescriptor();
}
@NotNull
@Override
public ClassDescriptor getClassDescriptor(@NotNull JetClassOrObject classOrObject) {
return resolveSession.getClassDescriptor(classOrObject);
}
@NotNull
@Override
public BindingContext getBindingContext() {
return resolveSession.getBindingContext();
}
@NotNull
@Override
public DeclarationDescriptor resolveToDescriptor(@NotNull JetDeclaration declaration) {
if (!JetPsiUtil.isLocal(declaration)) {
return resolveSession.resolveToDescriptor(declaration);
}
BindingContext context = resolveElementCache.resolveToElement(declaration);
return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, declaration,
"Descriptor wasn't found for declaration " + declaration.toString() + "\n" +
JetPsiUtil.getElementTextWithContext(declaration));
}
@Override
public void forceResolveAll() {
resolveSession.forceResolveAll();
}
@Override
public long getModificationCount() {
return resolveSession.getExceptionTracker().getModificationCount();
}
@Override
public String toString() {
return "ResolveSessionForBodies: " + getModificationCount() + " " + createdForObject + " " + createdForObject.hashCode();
}
@Override
@Nullable
public LazyPackageDescriptor getPackageFragment(@NotNull FqName fqName) {
return resolveSession.getPackageFragment(fqName);
}
@Override
@NotNull
@ReadOnly
public Collection<ClassDescriptor> getTopLevelClassDescriptors(@NotNull FqName fqName) {
return resolveSession.getTopLevelClassDescriptors(fqName);
}
@Override
@NotNull
public ScriptDescriptor getScriptDescriptor(@NotNull JetScript script) {
return resolveSession.getScriptDescriptor(script);
}
@Override
@NotNull
public ScopeProvider getScopeProvider() {
return resolveSession.getScopeProvider();
}
@NotNull
public StorageManager getStorageManager() {
return resolveSession.getStorageManager();
}
@NotNull
public ExceptionTracker getExceptionTracker() {
return resolveSession.getExceptionTracker();
}
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
public interface TargetPlatform {
TargetPlatform JVM = new TargetPlatformImpl("JVM");
TargetPlatform JS = new TargetPlatformImpl("JS");
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.analyzer.AnalyzerFacade;
import org.jetbrains.jet.lang.psi.JetFile;
public class TargetPlatformDetector {
public static final TargetPlatformDetector INSTANCE = new TargetPlatformDetector();
private static final Logger LOG = Logger.getInstance(AnalyzerFacade.class);
private TargetPlatformDetector() {
}
@NotNull
public static TargetPlatform getPlatform(@NotNull JetFile file) {
VirtualFile virtualFile = file.getOriginalFile().getVirtualFile();
if (virtualFile == null) {
return getDefaultPlatform();
}
Module moduleForFile = ProjectFileIndex.SERVICE.getInstance(file.getProject()).getModuleForFile(virtualFile);
if (moduleForFile == null) {
return getDefaultPlatform();
}
return getPlatform(moduleForFile);
}
@NotNull
public static TargetPlatform getPlatform(@NotNull Module module) {
if (ProjectStructureUtil.isJsKotlinModule(module)) {
return TargetPlatform.JS;
}
return TargetPlatform.JVM;
}
@NotNull
private static TargetPlatform getDefaultPlatform() {
LOG.info("Using default platform");
return TargetPlatform.JVM;
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.project;
import org.jetbrains.annotations.NotNull;
public class TargetPlatformImpl implements TargetPlatform {
@NotNull private final String platformName;
public TargetPlatformImpl(@NotNull String platformName) {
this.platformName = platformName;
}
@Override
public String toString() {
return platformName;
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.quickfix;
import com.intellij.codeInsight.intention.IntentionAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import java.util.List;
public interface JetIntentionActionsFactory {
@NotNull
List<IntentionAction> createActions(Diagnostic diagnostic);
}
@@ -0,0 +1,162 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.quickfix
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory
import org.jetbrains.jet.lang.psi.*
import org.jetbrains.jet.plugin.JetBundle
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import com.intellij.codeInspection.SuppressIntentionAction
import org.jetbrains.jet.plugin.util.JetPsiPrecedences
public class KotlinSuppressIntentionAction(
private val suppressAt: JetExpression,
private val diagnosticFactory: DiagnosticFactory<*>,
private val kind: AnnotationHostKind
) : SuppressIntentionAction() {
override fun getFamilyName() = JetBundle.message("suppress.warnings.family")
override fun getText() = JetBundle.message("suppress.warning.for", diagnosticFactory.getName(), kind.kind, kind.name)
override fun isAvailable(project: Project, editor: Editor?, element: PsiElement) = element.isValid()
override fun invoke(project: Project, editor: Editor?, element: PsiElement) {
val id = "\"${diagnosticFactory.getName()}\""
if (suppressAt is JetModifierListOwner) {
suppressAtModifierListOwner(suppressAt, id)
}
else if (suppressAt is JetAnnotatedExpression) {
suppressAtAnnotatedExpression(CaretBox(suppressAt, editor), id)
}
else if (suppressAt is JetExpression) {
suppressAtExpression(CaretBox(suppressAt, editor), id)
}
}
private fun suppressAtModifierListOwner(suppressAt: JetModifierListOwner, id: String) {
val modifierList = suppressAt.getModifierList()
val psiFactory = JetPsiFactory(suppressAt)
if (modifierList == null) {
// create a modifier list from scratch
val newModifierList = psiFactory.createModifierList(suppressAnnotationText(id))
val replaced = JetPsiUtil.replaceModifierList(suppressAt, newModifierList)
val whiteSpace = psiFactory.createWhiteSpace(kind)
suppressAt.addAfter(whiteSpace, replaced)
}
else {
val entry = findSuppressAnnotation(suppressAt)
if (entry == null) {
// no [suppress] annotation
val newAnnotation = psiFactory.createAnnotation(suppressAnnotationText(id))
val addedAnnotation = modifierList.addBefore(newAnnotation, modifierList.getFirstChild())
val whiteSpace = psiFactory.createWhiteSpace(kind)
modifierList.addAfter(whiteSpace, addedAnnotation)
}
else {
// already annotated with [suppress]
addArgumentToSuppressAnnotation(entry, id)
}
}
}
private fun suppressAtAnnotatedExpression(suppressAt: CaretBox<JetAnnotatedExpression>, id: String) {
val entry = findSuppressAnnotation(suppressAt.expression)
if (entry != null) {
// already annotated with [suppress]
addArgumentToSuppressAnnotation(entry, id)
}
else {
suppressAtExpression(suppressAt, id)
}
}
private fun suppressAtExpression(caretBox: CaretBox<JetExpression>, id: String) {
val suppressAt = caretBox.expression
assert(suppressAt !is JetDeclaration, "Declarations should have been checked for above")
val parentheses = JetPsiPrecedences.getPrecedence(suppressAt) > JetPsiPrecedences.PRECEDENCE_OF_PREFIX_EXPRESSION
val placeholderText = "PLACEHOLDER_ID"
val inner = if (parentheses) "($placeholderText)" else placeholderText
val annotatedExpression = JetPsiFactory(suppressAt).createExpression(suppressAnnotationText(id) + "\n" + inner)
val copy = suppressAt.copy()!!
val afterReplace = suppressAt.replace(annotatedExpression) as JetAnnotatedExpression
val toReplace = afterReplace.findElementAt(afterReplace.getTextLength() - 2)!!
assert (toReplace.getText() == placeholderText)
val result = toReplace.replace(copy)!!
caretBox.positionCaretInCopy(result)
}
private fun addArgumentToSuppressAnnotation(entry: JetAnnotationEntry, id: String) {
// add new arguments to an existing entry
val args = entry.getValueArgumentList()
val psiFactory = JetPsiFactory(entry)
val newArgList = psiFactory.createCallArguments("($id)")
if (args == null) {
// new argument list
entry.addAfter(newArgList, entry.getLastChild())
}
else if (args.getArguments().isEmpty()) {
// replace '()' with a new argument list
args.replace(newArgList)
}
else {
val rightParen = args.getRightParenthesis()
args.addBefore(psiFactory.createComma(), rightParen)
args.addBefore(psiFactory.createWhiteSpace(), rightParen)
args.addBefore(newArgList.getArguments()[0], rightParen)
}
}
private fun suppressAnnotationText(id: String) = "[suppress($id)]"
private fun findSuppressAnnotation(annotated: JetAnnotated): JetAnnotationEntry? {
val context = AnalyzerFacadeWithCache.getContextForElement(annotated)
for (entry in annotated.getAnnotationEntries()) {
val annotationDescriptor = context.get(BindingContext.ANNOTATION, entry)
if (annotationDescriptor != null && KotlinBuiltIns.getInstance().isSuppressAnnotation(annotationDescriptor)) {
return entry
}
}
return null
}
}
public class AnnotationHostKind(val kind: String, val name: String, val newLineNeeded: Boolean)
private fun JetPsiFactory.createWhiteSpace(kind: AnnotationHostKind): PsiElement {
return if (kind.newLineNeeded) createNewLine() else createWhiteSpace()
}
private class CaretBox<out E: JetExpression>(
val expression: E,
private val editor: Editor?
) {
private val offsetInExpression: Int = (editor?.getCaretModel()?.getOffset() ?: 0) - expression.getTextRange()!!.getStartOffset()
fun positionCaretInCopy(copy: PsiElement) {
if (editor == null) return
editor.getCaretModel().moveToOffset(copy.getTextOffset() + offsetInExpression)
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.quickfix;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.intellij.codeInsight.intention.IntentionAction;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
import java.util.Collection;
public class QuickFixes {
static final Multimap<DiagnosticFactory<?>, JetIntentionActionsFactory> factories = HashMultimap.create();
static final Multimap<DiagnosticFactory<?>, IntentionAction> actions = HashMultimap.create();
public static Collection<JetIntentionActionsFactory> getActionsFactories(DiagnosticFactory<?> diagnosticFactory) {
return factories.get(diagnosticFactory);
}
public static Collection<IntentionAction> getActions(DiagnosticFactory<?> diagnosticFactory) {
return actions.get(diagnosticFactory);
}
private QuickFixes() {}
}
@@ -0,0 +1,262 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.references;
import com.google.common.base.Predicates;
import com.google.common.collect.Sets;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.context.ContextPackage;
import org.jetbrains.jet.context.GlobalContextImpl;
import org.jetbrains.jet.di.InjectorForTopDownAnalyzerBasic;
import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import org.jetbrains.jet.utils.UtilsPackage;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.unwrapFakeOverride;
public class BuiltInsReferenceResolver extends AbstractProjectComponent {
private static final File BUILT_INS_COMPILABLE_SRC_DIR =
new File("core/builtins/src", KotlinBuiltIns.BUILT_INS_PACKAGE_NAME.asString());
private volatile BindingContext bindingContext;
private volatile Set<JetFile> builtInsSources;
private volatile MutablePackageFragmentDescriptor builtinsPackageFragment;
public BuiltInsReferenceResolver(Project project) {
super(project);
}
@Override
public void initComponent() {
StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
@Override
public void run() {
initialize();
}
});
}
@TestOnly
public Set<JetFile> getBuiltInsSources() {
return builtInsSources;
}
private void initialize() {
assert bindingContext == null : "Attempt to initialize twice";
final Set<JetFile> jetBuiltInsFiles = getJetBuiltInsFiles();
final Runnable initializeRunnable = new Runnable() {
@Override
public void run() {
GlobalContextImpl globalContext = ContextPackage.GlobalContext();
TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.create(
globalContext.getStorageManager(),
globalContext.getExceptionTracker(),
Predicates.<PsiFile>alwaysFalse(), true, false);
ModuleDescriptorImpl module = new ModuleDescriptorImpl(
Name.special("<fake_module>"), Collections.<ImportPath>emptyList(), PlatformToKotlinClassMap.EMPTY);
module.addDependencyOnModule(module);
module.seal();
BindingTraceContext trace = new BindingTraceContext();
InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
myProject, topDownAnalysisParameters, trace, module);
TopDownAnalyzer analyzer = injector.getTopDownAnalyzer();
analyzer.analyzeFiles(topDownAnalysisParameters, jetBuiltInsFiles);
builtinsPackageFragment = analyzer.getPackageFragmentProvider().getOrCreateFragment(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME);
builtInsSources = Sets.newHashSet(jetBuiltInsFiles);
bindingContext = trace.getBindingContext();
}
};
if (ApplicationManager.getApplication().isUnitTestMode()) {
initializeRunnable.run();
}
else {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runReadAction(initializeRunnable);
}
});
}
}
@NotNull
private Set<JetFile> getJetBuiltInsFiles() {
Set<JetFile> builtIns = getBuiltInSourceFiles(LightClassUtil.getBuiltInsDirUrl());
if (ApplicationManager.getApplication().isUnitTestMode()) {
// In production, the above URL is enough as it contains sources for both native and compilable built-ins
// (it's simply the "kotlin" directory in kotlin-plugin.jar)
// But in tests, sources of built-ins are not added to the classpath automatically, so we manually specify URLs for both:
// LightClassUtil.getBuiltInsDirUrl() does so for native built-ins and the code below for compilable built-ins
try {
builtIns.addAll(getBuiltInSourceFiles(BUILT_INS_COMPILABLE_SRC_DIR.toURI().toURL()));
}
catch (MalformedURLException e) {
throw UtilsPackage.rethrow(e);
}
}
return builtIns;
}
@NotNull
private Set<JetFile> getBuiltInSourceFiles(@NotNull URL url) {
String fromUrl = VfsUtilCore.convertFromUrl(url);
VirtualFile vf = VirtualFileManager.getInstance().findFileByUrl(fromUrl);
assert vf != null : "Virtual file not found by URL: " + url;
// Refreshing VFS: in case the plugin jar was updated, the caches may hold the old value
vf.getChildren();
vf.refresh(false, true);
PathUtil.getLocalFile(vf).refresh(false, true);
PsiDirectory psiDirectory = PsiManager.getInstance(myProject).findDirectory(vf);
assert psiDirectory != null : "No PsiDirectory for " + vf;
return new HashSet<JetFile>(ContainerUtil.mapNotNull(psiDirectory.getFiles(), new Function<PsiFile, JetFile>() {
@Override
public JetFile fun(PsiFile file) {
return file instanceof JetFile ? (JetFile) file : null;
}
}));
}
@Nullable
private DeclarationDescriptor findCurrentDescriptorForClass(@NotNull ClassDescriptor originalDescriptor) {
// BindingContext doesn't contain an information about class descriptor of class object. For example see testEmptyRange.
if (DescriptorUtils.isClassObject(originalDescriptor)) {
DeclarationDescriptor currentParent = findCurrentDescriptor(originalDescriptor.getContainingDeclaration());
if (currentParent == null) return null;
return ((ClassDescriptor) currentParent).getClassObjectDescriptor();
}
return bindingContext.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, DescriptorUtils.getFqName(originalDescriptor));
}
@Nullable
private DeclarationDescriptor findCurrentDescriptorForMember(@NotNull MemberDescriptor originalDescriptor) {
if (originalDescriptor instanceof CallableMemberDescriptor &&
((CallableMemberDescriptor) originalDescriptor).getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
return findCurrentDescriptorForMember(unwrapFakeOverride((CallableMemberDescriptor) originalDescriptor).getOriginal());
}
DeclarationDescriptor containingDeclaration = findCurrentDescriptor(originalDescriptor.getContainingDeclaration());
JetScope memberScope = getMemberScope(containingDeclaration);
if (memberScope == null) return null;
String renderedOriginal = DescriptorRenderer.FQ_NAMES_IN_TYPES.render(originalDescriptor);
Collection<? extends DeclarationDescriptor> descriptors;
if (originalDescriptor instanceof ConstructorDescriptor && containingDeclaration instanceof ClassDescriptor) {
descriptors = ((ClassDescriptor) containingDeclaration).getConstructors();
}
else {
descriptors = memberScope.getAllDescriptors();
}
for (DeclarationDescriptor member : descriptors) {
if (renderedOriginal.equals(DescriptorRenderer.FQ_NAMES_IN_TYPES.render(member))) {
return member;
}
}
return null;
}
@Nullable
private DeclarationDescriptor findCurrentDescriptor(@NotNull DeclarationDescriptor originalDescriptor) {
if (originalDescriptor instanceof ClassDescriptor) {
return findCurrentDescriptorForClass((ClassDescriptor) originalDescriptor);
}
else if (originalDescriptor instanceof PackageFragmentDescriptor) {
return KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.equals(((PackageFragmentDescriptor) originalDescriptor).getFqName())
? builtinsPackageFragment
: null;
}
else if (originalDescriptor instanceof MemberDescriptor) {
return findCurrentDescriptorForMember((MemberDescriptor) originalDescriptor);
}
else {
return null;
}
}
@NotNull
public Collection<PsiElement> resolveBuiltInSymbol(@NotNull DeclarationDescriptor declarationDescriptor) {
if (bindingContext == null) {
return Collections.emptyList();
}
DeclarationDescriptor descriptor = findCurrentDescriptor(declarationDescriptor.getOriginal());
if (descriptor != null) {
return DescriptorToSourceUtils.descriptorToDeclarations(descriptor);
}
return Collections.emptyList();
}
public static boolean isFromBuiltIns(@NotNull PsiElement element) {
return element.getProject().getComponent(BuiltInsReferenceResolver.class).builtInsSources.contains(element.getContainingFile());
}
@Nullable
private static JetScope getMemberScope(@Nullable DeclarationDescriptor parent) {
if (parent instanceof ClassDescriptor) {
return ((ClassDescriptor) parent).getDefaultType().getMemberScope();
}
else if (parent instanceof PackageFragmentDescriptor) {
return ((PackageFragmentDescriptor) parent).getMemberScope();
}
else {
return null;
}
}
}
@@ -0,0 +1,150 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.references
import com.intellij.psi.PsiPolyVariantReference
import com.intellij.psi.PsiPolyVariantReferenceBase
import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveResult
import com.intellij.psi.PsiElementResolveResult
import com.intellij.util.IncorrectOperationException
import com.intellij.psi.PsiReference
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import java.util.Collections
import java.util.HashSet
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor
import com.intellij.psi.JavaPsiFacade
import org.jetbrains.jet.lang.psi.JetReferenceExpression
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.utils.keysToMap
import org.jetbrains.jet.plugin.search.allScope
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
public trait JetReference : PsiPolyVariantReference {
public fun resolveToDescriptors(): Collection<DeclarationDescriptor>
public fun resolveMap(): Map<DeclarationDescriptor, Collection<PsiElement>>
}
public abstract class AbstractJetReference<T : JetElement>(element: T)
: PsiPolyVariantReferenceBase<T>(element), JetReference {
val expression: T
get() = getElement()
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> {
return PsiElementResolveResult.createResults(resolveToPsiElements())
}
override fun resolve(): PsiElement? {
val psiElements = resolveToPsiElements()
if (psiElements.size() == 1) {
return psiElements.iterator().next()
}
return null
}
override fun isReferenceTo(element: PsiElement?): Boolean {
return element != null && matchesTarget(element)
}
override fun getCanonicalText(): String = "<TBD>"
open fun canRename(): Boolean = false
override fun handleElementRename(newElementName: String?): PsiElement? = throw IncorrectOperationException()
override fun bindToElement(element: PsiElement): PsiElement = throw IncorrectOperationException()
[suppress("CAST_NEVER_SUCCEEDS")]
override fun getVariants(): Array<Any> = PsiReference.EMPTY_ARRAY as Array<Any>
override fun isSoft(): Boolean = false
private fun resolveToPsiElements(): Collection<PsiElement> {
val context = AnalyzerFacadeWithCache.getContextForElement(expression)
return resolveToPsiElements(context, getTargetDescriptors(context))
}
override fun resolveToDescriptors(): Collection<DeclarationDescriptor> {
val context = AnalyzerFacadeWithCache.getContextForElement(expression)
return getTargetDescriptors(context)
}
override fun resolveMap(): Map<DeclarationDescriptor, Collection<PsiElement>> {
val context = AnalyzerFacadeWithCache.getContextForElement(expression)
return getTargetDescriptors(context) keysToMap { resolveToPsiElements(it) }
}
private fun resolveToPsiElements(context: BindingContext, targetDescriptors: Collection<DeclarationDescriptor>): Collection<PsiElement> {
if (targetDescriptors.isNotEmpty()) {
return targetDescriptors flatMap { target -> resolveToPsiElements(target) }
}
val labelTargets = getLabelTargets(context)
if (labelTargets != null) {
return labelTargets
}
return Collections.emptySet()
}
private fun resolveToPsiElements(targetDescriptor: DeclarationDescriptor): Collection<PsiElement> {
val result = HashSet<PsiElement>()
val project = expression.getProject()
// todo: remove getOriginal()
val originalDescriptor = targetDescriptor.getOriginal()
result.addAll(DescriptorToSourceUtils.descriptorToDeclarations(originalDescriptor))
result.addAll(DescriptorToDeclarationUtil.findDecompiledAndBuiltInDeclarations(project, originalDescriptor))
if (originalDescriptor is PackageViewDescriptor) {
val psiFacade = JavaPsiFacade.getInstance(project)
val fqName = (originalDescriptor as PackageViewDescriptor).getFqName().asString()
ContainerUtil.addIfNotNull(result, psiFacade.findPackage(fqName))
ContainerUtil.addIfNotNull(result, psiFacade.findClass(fqName, project.allScope()))
}
return result
}
protected abstract fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor>
private fun getLabelTargets(context: BindingContext): Collection<PsiElement>? {
val reference = expression
if (reference !is JetReferenceExpression) {
return null
}
val labelTarget = context[BindingContext.LABEL_TARGET, reference]
if (labelTarget != null) {
return listOf(labelTarget)
}
return context[BindingContext.AMBIGUOUS_LABEL_TARGET, reference]
}
}
public abstract class JetSimpleReference<T : JetReferenceExpression>(expression: T) : AbstractJetReference<T>(expression) {
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val targetDescriptor = context[BindingContext.REFERENCE_TARGET, expression]
if (targetDescriptor != null) {
return listOf(targetDescriptor)
}
return context[BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression].orEmpty()
}
}
public abstract class JetMultiReference<T : JetElement>(expression: T) : AbstractJetReference<T>(expression)
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.references
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiElement
import org.jetbrains.jet.asJava.unwrapped
import com.intellij.psi.PsiMethod
import org.jetbrains.jet.lang.psi.JetPropertyAccessor
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
import org.jetbrains.jet.lang.psi.JetProperty
import java.util.HashSet
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.plugin.intentions.OperatorToFunctionIntention
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
import org.jetbrains.jet.lang.psi.JetCallExpression
import com.intellij.psi.util.PsiTreeUtil
// Navigation element of the resolved reference
// For property accessor return enclosing property
val PsiReference.unwrappedTargets: Set<PsiElement>
get() {
fun PsiElement.adjust(): PsiElement? {
val target = unwrapped
return if (target is JetPropertyAccessor) target.getParentByType(javaClass<JetProperty>()) else target
}
return when (this) {
is JetMultiReference<*> -> multiResolve(false).map { it.getElement()?.adjust() }.filterNotNullTo(HashSet<PsiElement>())
else -> ContainerUtil.createMaybeSingletonSet(resolve()?.adjust())
}
}
fun PsiReference.matchesTarget(target: PsiElement): Boolean {
val unwrapped = target.unwrapped
return when {
unwrapped in unwrappedTargets ->
true
this is JetReference
&& unwrappedTargets.any { it is PsiMethod && it.isConstructor() && it.getContainingClass() == unwrapped } ->
true
else ->
false
}
}
fun AbstractJetReference<out JetExpression>.renameImplicitConventionalCall(newName: String?): JetExpression {
if (newName == null) return expression
val expr = OperatorToFunctionIntention.convert(expression) as JetQualifiedExpression
val newCallee = (expr.getSelectorExpression() as JetCallExpression).getCalleeExpression()!!.getReference()!!.handleElementRename(newName)
return PsiTreeUtil.getParentOfType<JetQualifiedExpression>(newCallee, javaClass<JetQualifiedExpression>()) as JetExpression
}
@@ -0,0 +1,33 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.search
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.intellij.psi.search.SearchScope
fun SearchScope.and(otherScope: SearchScope): SearchScope = intersectWith(otherScope)
fun SearchScope.or(otherScope: SearchScope): SearchScope = union(otherScope)
fun SearchScope.minus(otherScope: GlobalSearchScope) = this and !otherScope
fun GlobalSearchScope.not(): GlobalSearchScope = GlobalSearchScope.notScope(this)
fun Project.allScope(): GlobalSearchScope = GlobalSearchScope.allScope(this)
fun Project.projectScope(): GlobalSearchScope = GlobalSearchScope.projectScope(this)
fun PsiFile.fileScope(): GlobalSearchScope = GlobalSearchScope.fileScope(this)
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import java.util.Collection;
/**
* Contains all packages, i.e. if a file declares
* package a.b.c
*
* Three packages "a", "a.b" and "a.b.c" will be registered in this index
*/
public class JetAllPackagesIndex extends StringStubIndexExtension<JetFile> {
private static final StubIndexKey<String, JetFile> KEY = KotlinIndexUtil.createIndexKey(JetAllPackagesIndex.class);
private static final JetAllPackagesIndex ourInstance = new JetAllPackagesIndex();
@NotNull
public static JetAllPackagesIndex getInstance() {
return ourInstance;
}
private JetAllPackagesIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetFile> getKey() {
return KEY;
}
@NotNull
@Override
public Collection<JetFile> get(String fqName, Project project, @NotNull GlobalSearchScope scope) {
return super.get(fqName, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetAnnotationEntry;
import java.util.Collection;
public class JetAnnotationsIndex extends StringStubIndexExtension<JetAnnotationEntry> {
private static final StubIndexKey<String, JetAnnotationEntry> KEY = KotlinIndexUtil.createIndexKey(JetAnnotationsIndex.class);
private static final JetAnnotationsIndex ourInstance = new JetAnnotationsIndex();
public static JetAnnotationsIndex getInstance() {
return ourInstance;
}
private JetAnnotationsIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetAnnotationEntry> getKey() {
return KEY;
}
@Override
public Collection<JetAnnotationEntry> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import java.util.Collection;
public class JetClassByPackageIndex extends StringStubIndexExtension<JetClassOrObject> {
private static final StubIndexKey<String, JetClassOrObject> KEY = KotlinIndexUtil.createIndexKey(JetClassByPackageIndex.class);
private static final JetClassByPackageIndex ourInstance = new JetClassByPackageIndex();
public static JetClassByPackageIndex getInstance() {
return ourInstance;
}
private JetClassByPackageIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetClassOrObject> getKey() {
return KEY;
}
@Override
public Collection<JetClassOrObject> get(String fqName, Project project, @NotNull GlobalSearchScope scope) {
return super.get(fqName, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import java.util.Collection;
public class JetClassShortNameIndex extends StringStubIndexExtension<JetClassOrObject> {
private static final StubIndexKey<String, JetClassOrObject> KEY = KotlinIndexUtil.createIndexKey(JetClassShortNameIndex.class);
private static final JetClassShortNameIndex ourInstance = new JetClassShortNameIndex();
public static JetClassShortNameIndex getInstance() {
return ourInstance;
}
private JetClassShortNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetClassOrObject> getKey() {
return KEY;
}
@Override
public Collection<JetClassOrObject> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import java.util.Collection;
public class JetFullClassNameIndex extends StringStubIndexExtension<JetClassOrObject> {
private static final StubIndexKey<String, JetClassOrObject> KEY = KotlinIndexUtil.createIndexKey(JetFullClassNameIndex.class);
private static final JetFullClassNameIndex ourInstance = new JetFullClassNameIndex();
@NotNull
public static JetFullClassNameIndex getInstance() {
return ourInstance;
}
private JetFullClassNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetClassOrObject> getKey() {
return KEY;
}
@NotNull
@Override
public Collection<JetClassOrObject> get(String fqName, Project project, @NotNull GlobalSearchScope scope) {
return super.get(fqName, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import java.util.Collection;
public class JetFunctionShortNameIndex extends StringStubIndexExtension<JetNamedFunction> {
private static final StubIndexKey<String, JetNamedFunction> KEY = KotlinIndexUtil.createIndexKey(JetFunctionShortNameIndex.class);
private static final JetFunctionShortNameIndex ourInstance = new JetFunctionShortNameIndex();
public static JetFunctionShortNameIndex getInstance() {
return ourInstance;
}
private JetFunctionShortNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetNamedFunction> getKey() {
return KEY;
}
@Override
public Collection<JetNamedFunction> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetProperty;
import java.util.Collection;
public class JetPropertyShortNameIndex extends StringStubIndexExtension<JetProperty> {
private static final StubIndexKey<String, JetProperty> KEY = KotlinIndexUtil.createIndexKey(JetPropertyShortNameIndex.class);
private static final JetPropertyShortNameIndex ourInstance = new JetPropertyShortNameIndex();
public static JetPropertyShortNameIndex getInstance() {
return ourInstance;
}
private JetPropertyShortNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetProperty> getKey() {
return KEY;
}
@Override
public Collection<JetProperty> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.ide.highlighter.JavaClassFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.DelegatingGlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.configuration.JetModuleTypeManager;
public class JetSourceFilterScope extends DelegatingGlobalSearchScope {
@NotNull
public static GlobalSearchScope kotlinSourcesAndLibraries(@NotNull GlobalSearchScope delegate, @NotNull Project project) {
return new JetSourceFilterScope(delegate, true, project);
}
@NotNull
public static GlobalSearchScope kotlinSources(@NotNull GlobalSearchScope delegate, @NotNull Project project) {
return new JetSourceFilterScope(delegate, false, project);
}
private final ProjectFileIndex index;
private final Project project;
private final boolean includeLibraries;
private JetSourceFilterScope(@NotNull GlobalSearchScope delegate, boolean includeLibraries, @NotNull Project project) {
super(delegate);
this.includeLibraries = includeLibraries;
this.index = ProjectRootManager.getInstance(project).getFileIndex();
this.project = project;
}
@Override
public boolean contains(@NotNull VirtualFile file) {
if (!super.contains(file)) {
return false;
}
if (includeLibraries && JavaClassFileType.INSTANCE == file.getFileType()) {
return index.isInLibraryClasses(file);
}
if (JetModuleTypeManager.getInstance().isKtFileInGradleProjectInWrongFolder(file, getProject())) {
return false;
}
return file.getFileType().equals(JetFileType.INSTANCE) &&
(index.isInSourceContent(file) || includeLibraries && index.isInLibrarySource(file));
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import java.util.Collection;
public class JetSuperClassIndex extends StringStubIndexExtension<JetClassOrObject> {
private static final StubIndexKey<String, JetClassOrObject> KEY = KotlinIndexUtil.createIndexKey(JetSuperClassIndex.class);
private static final JetSuperClassIndex ourInstance = new JetSuperClassIndex();
@NotNull
public static JetSuperClassIndex getInstance() {
return ourInstance;
}
private JetSuperClassIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetClassOrObject> getKey() {
return KEY;
}
@NotNull
@Override
public Collection<JetClassOrObject> get(String s, Project project, GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
public class JetTopLevelExtensionFunctionShortNameIndex extends StringStubIndexExtension<JetNamedFunction> {
private static final StubIndexKey<String, JetNamedFunction> KEY = KotlinIndexUtil.createIndexKey(JetTopLevelExtensionFunctionShortNameIndex.class);
private static final JetTopLevelExtensionFunctionShortNameIndex instance = new JetTopLevelExtensionFunctionShortNameIndex();
public static JetTopLevelExtensionFunctionShortNameIndex getInstance() {
return instance;
}
private JetTopLevelExtensionFunctionShortNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetNamedFunction> getKey() {
return KEY;
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import java.util.Collection;
/**
* Stores package top level function (both extension and non-extension) full qualified names.
*/
public class JetTopLevelFunctionsFqnNameIndex extends StringStubIndexExtension<JetNamedFunction> {
private static final StubIndexKey<String, JetNamedFunction> KEY = KotlinIndexUtil.createIndexKey(JetTopLevelFunctionsFqnNameIndex.class);
private static final JetTopLevelFunctionsFqnNameIndex INSTANCE = new JetTopLevelFunctionsFqnNameIndex();
@NotNull
public static JetTopLevelFunctionsFqnNameIndex getInstance() {
return INSTANCE;
}
private JetTopLevelFunctionsFqnNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetNamedFunction> getKey() {
return KEY;
}
@NotNull
@Override
public Collection<JetNamedFunction> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import java.util.Collection;
public class JetTopLevelNonExtensionFunctionShortNameIndex extends StringStubIndexExtension<JetNamedFunction> {
private static final StubIndexKey<String, JetNamedFunction> KEY = KotlinIndexUtil.createIndexKey(JetTopLevelNonExtensionFunctionShortNameIndex.class);
private static final JetTopLevelNonExtensionFunctionShortNameIndex ourInstance = new JetTopLevelNonExtensionFunctionShortNameIndex();
public static JetTopLevelNonExtensionFunctionShortNameIndex getInstance() {
return ourInstance;
}
private JetTopLevelNonExtensionFunctionShortNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetNamedFunction> getKey() {
return KEY;
}
@Override
public Collection<JetNamedFunction> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import java.util.Collection;
public class JetTopLevelObjectShortNameIndex extends StringStubIndexExtension<JetObjectDeclaration> {
private static final StubIndexKey<String, JetObjectDeclaration> KEY = KotlinIndexUtil.createIndexKey(JetTopLevelObjectShortNameIndex.class);
private static final JetTopLevelObjectShortNameIndex ourInstance = new JetTopLevelObjectShortNameIndex();
public static JetTopLevelObjectShortNameIndex getInstance() {
return ourInstance;
}
private JetTopLevelObjectShortNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetObjectDeclaration> getKey() {
return KEY;
}
@Override
public Collection<JetObjectDeclaration> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetProperty;
import java.util.Collection;
public class JetTopLevelPropertiesFqnNameIndex extends StringStubIndexExtension<JetProperty> {
private static final StubIndexKey<String, JetProperty> KEY = KotlinIndexUtil.createIndexKey(JetTopLevelPropertiesFqnNameIndex.class);
private static final JetTopLevelPropertiesFqnNameIndex INSTANCE = new JetTopLevelPropertiesFqnNameIndex();
@NotNull
public static JetTopLevelPropertiesFqnNameIndex getInstance() {
return INSTANCE;
}
private JetTopLevelPropertiesFqnNameIndex() {}
@NotNull
@Override
public StubIndexKey<String, JetProperty> getKey() {
return KEY;
}
@NotNull
@Override
public Collection<JetProperty> get(String s, Project project, @NotNull GlobalSearchScope scope) {
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.psi.PsiElement;
import com.intellij.psi.stubs.StubIndexExtension;
import com.intellij.psi.stubs.StubIndexKey;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class KotlinIndexUtil {
@NonNls
public static <K, Psi extends PsiElement> StubIndexKey<K, Psi> createIndexKey(@NotNull Class<? extends StubIndexExtension<K, Psi>> indexClass) {
return StubIndexKey.createIndexKey(indexClass.getCanonicalName());
}
private KotlinIndexUtil() {}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.NamePackage;
import java.util.Collection;
import java.util.Set;
public final class PackageIndexUtil {
@NotNull
public static Collection<FqName> getSubPackageFqNames(
@NotNull FqName packageFqName,
@NotNull GlobalSearchScope scope,
@NotNull Project project
) {
Collection<JetFile> files = JetAllPackagesIndex.getInstance().get(packageFqName.asString(), project, scope);
Set<FqName> result = Sets.newHashSet();
for (JetFile file : files) {
FqName fqName = file.getPackageFqName();
assert NamePackage.isSubpackageOf(fqName, packageFqName) :
"Registered package is not a subpackage of actually declared package:\n" +
"in index: " + packageFqName + "\n" +
"declared: " + fqName;
FqName subpackage = NamePackage.plusOneSegment(packageFqName, fqName);
if (subpackage != null) {
result.add(subpackage);
}
}
return result;
}
@NotNull
public static Collection<JetFile> findFilesWithExactPackage(
@NotNull final FqName packageFqName,
@NotNull GlobalSearchScope searchScope,
@NotNull Project project
) {
Collection<JetFile> files = JetAllPackagesIndex.getInstance().get(packageFqName.asString(), project, searchScope);
return ContainerUtil.filter(files, new Condition<JetFile>() {
@Override
public boolean value(JetFile file) {
return packageFqName.equals(file.getPackageFqName());
}
});
}
private PackageIndexUtil() {
}
}
@@ -0,0 +1,149 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex;
import com.intellij.psi.stubs.IndexSink;
import com.intellij.psi.stubs.StubElement;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.stubs.*;
import org.jetbrains.jet.lang.psi.stubs.elements.StubIndexService;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
public class StubIndexServiceImpl implements StubIndexService {
@Override
public void indexFile(PsiJetFileStub stub, IndexSink sink) {
FqName packageFqName = stub.getPackageFqName();
while (true) {
sink.occurrence(JetAllPackagesIndex.getInstance().getKey(), packageFqName.asString());
if (packageFqName.isRoot()) {
return;
}
packageFqName = packageFqName.parent();
}
}
@Override
public void indexClass(PsiJetClassStub stub, IndexSink sink) {
String name = stub.getName();
if (name != null) {
sink.occurrence(JetClassShortNameIndex.getInstance().getKey(), name);
}
FqName fqn = stub.getFqName();
if (fqn != null) {
sink.occurrence(JetFullClassNameIndex.getInstance().getKey(), fqn.asString());
}
indexSuperNames(stub, sink);
recordClassOrObjectByPackage(stub, sink);
}
@Override
public void indexObject(PsiJetObjectStub stub, IndexSink sink) {
String name = stub.getName();
FqName fqName = stub.getFqName();
if (stub.isClassObject()) {
StubElement parentClassStub = stub.getParentStub().getParentStub().getParentStub();
assert parentClassStub instanceof PsiJetStubWithFqName<?>
: "Something but a class/object is a parent to class object stub: " + parentClassStub;
name = JvmAbi.CLASS_OBJECT_CLASS_NAME;
FqName parentFqName = ((PsiJetStubWithFqName<?>) parentClassStub).getFqName();
if (parentFqName != null) {
fqName = parentFqName.child(Name.identifier(name));
}
}
if (name != null) {
sink.occurrence(JetClassShortNameIndex.getInstance().getKey(), name);
if (stub.isTopLevel()) {
sink.occurrence(JetTopLevelObjectShortNameIndex.getInstance().getKey(), name);
}
}
if (fqName != null) {
sink.occurrence(JetFullClassNameIndex.getInstance().getKey(), fqName.asString());
}
indexSuperNames(stub, sink);
recordClassOrObjectByPackage(stub, sink);
}
private static void indexSuperNames(PsiJetClassOrObjectStub<? extends JetClassOrObject> stub, IndexSink sink) {
for (String superName : stub.getSuperNames()) {
sink.occurrence(JetSuperClassIndex.getInstance().getKey(), superName);
}
}
private static void recordClassOrObjectByPackage(StubElement<? extends JetClassOrObject> stub, IndexSink sink) {
StubElement parentStub = stub.getParentStub();
if (parentStub instanceof PsiJetFileStub) {
PsiJetFileStub jetFileStub = (PsiJetFileStub) parentStub;
FqName packageFqName = jetFileStub.getPackageFqName();
sink.occurrence(JetClassByPackageIndex.getInstance().getKey(), packageFqName.asString());
}
}
@Override
public void indexFunction(PsiJetFunctionStub stub, IndexSink sink) {
String name = stub.getName();
if (name != null) {
if (stub.isTopLevel()) {
// Collection only top level functions as only they are expected in completion without explicit import
if (!stub.isExtension()) {
sink.occurrence(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getKey(), name);
}
else {
sink.occurrence(JetTopLevelExtensionFunctionShortNameIndex.getInstance().getKey(), name);
}
}
sink.occurrence(JetFunctionShortNameIndex.getInstance().getKey(), name);
}
// can have special fq name in case of syntactically incorrect function with no name
FqName topFQName = stub.getFqName();
if (topFQName != null) {
sink.occurrence(JetTopLevelFunctionsFqnNameIndex.getInstance().getKey(), topFQName.asString());
}
}
@Override
public void indexProperty(PsiJetPropertyStub stub, IndexSink sink) {
String propertyName = stub.getName();
if (propertyName != null) {
sink.occurrence(JetPropertyShortNameIndex.getInstance().getKey(), propertyName);
}
// can have special fq name in case of syntactically incorrect function with no name
if (stub.isTopLevel()) {
FqName topFQName = stub.getFqName();
if (topFQName != null) {
sink.occurrence(JetTopLevelPropertiesFqnNameIndex.getInstance().getKey(), topFQName.asString());
}
}
}
@Override
public void indexAnnotation(PsiJetAnnotationEntryStub stub, IndexSink sink) {
sink.occurrence(JetAnnotationsIndex.getInstance().getKey(), stub.getShortName());
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex.resolve
import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider
import org.jetbrains.jet.lang.resolve.name.Name
public class CombinedPackageMemberDeclarationProvider(val providers: Collection<PackageMemberDeclarationProvider>) : PackageMemberDeclarationProvider {
override fun getAllDeclaredSubPackages() = providers.flatMap { it.getAllDeclaredSubPackages() }
override fun getPackageFiles() = providers.flatMap { it.getPackageFiles() }
override fun getAllDeclarations() = providers.flatMap { it.getAllDeclarations() }
override fun getFunctionDeclarations(name: Name) = providers.flatMap { it.getFunctionDeclarations(name) }
override fun getPropertyDeclarations(name: Name) = providers.flatMap { it.getPropertyDeclarations(name) }
override fun getClassOrObjectDeclarations(name: Name) = providers.flatMap { it.getClassOrObjectDeclarations(name) }
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex.resolve
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo
import org.jetbrains.jet.lang.resolve.lazy.declarations.*
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.plugin.stubindex.JetAllPackagesIndex
import org.jetbrains.jet.storage.StorageManager
public class PluginDeclarationProviderFactory(
private val project: Project,
private val indexedFilesScope: GlobalSearchScope,
private val storageManager: StorageManager,
private val nonIndexedFiles: Collection<JetFile>
) : AbstractDeclarationProviderFactory(storageManager) {
private val fileBasedDeclarationProviderFactory = FileBasedDeclarationProviderFactory(storageManager, nonIndexedFiles)
override fun getClassMemberDeclarationProvider(classLikeInfo: JetClassLikeInfo): ClassMemberDeclarationProvider {
return PsiBasedClassMemberDeclarationProvider(storageManager, classLikeInfo)
}
override fun createPackageMemberDeclarationProvider(name: FqName): PackageMemberDeclarationProvider? {
val fileBasedProvider = fileBasedDeclarationProviderFactory.getPackageMemberDeclarationProvider(name)
val stubBasedProvider = getStubBasedPackageMemberDeclarationProvider(name)
return when {
fileBasedProvider == null && stubBasedProvider == null -> null
fileBasedProvider == null -> stubBasedProvider
stubBasedProvider == null -> fileBasedProvider
else -> CombinedPackageMemberDeclarationProvider(listOf(stubBasedProvider, fileBasedProvider))
}
}
private fun getStubBasedPackageMemberDeclarationProvider(name: FqName): PackageMemberDeclarationProvider? {
//TODO: better check
val files = JetAllPackagesIndex.getInstance().get(name.asString(), project, indexedFilesScope)
if (files.isEmpty()) {
return null
}
return StubBasedPackageMemberDeclarationProvider(name, project, indexedFilesScope)
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex.resolve
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.jet.storage.StorageManager
import org.jetbrains.jet.plugin.stubindex.JetSourceFilterScope
public class PluginDeclarationProviderFactoryService : DeclarationProviderFactoryService() {
override fun create(
project: Project,
storageManager: StorageManager,
syntheticFiles: Collection<JetFile>,
filesScope: GlobalSearchScope
): DeclarationProviderFactory {
return PluginDeclarationProviderFactory(project, JetSourceFilterScope.kotlinSources(filesScope, project),
storageManager, syntheticFiles)
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.stubindex.resolve
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StringStubIndexExtension
import org.jetbrains.jet.lang.psi.*
import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex
import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex
import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex
import org.jetbrains.jet.plugin.stubindex.PackageIndexUtil
import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo
import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
public class StubBasedPackageMemberDeclarationProvider(
private val fqName: FqName,
private val project: Project,
private val searchScope: GlobalSearchScope
) : PackageMemberDeclarationProvider {
override fun getAllDeclarations(): List<JetDeclaration> {
return TOP_LEVEL_DECLARATION_INDICES.flatMap {
index ->
val fqNames = index.getAllKeys(project).toSet().map { FqName(it) }.filter { !it.isRoot() && it.parent() == fqName }
fqNames.flatMap { index.get(it.asString(), project, searchScope) }
}
}
override fun getClassOrObjectDeclarations(name: Name): Collection<JetClassLikeInfo> {
return JetFullClassNameIndex.getInstance().get(childName(name), project, searchScope)
.map { JetClassInfoUtil.createClassLikeInfo(it) }
}
override fun getFunctionDeclarations(name: Name): Collection<JetNamedFunction> {
return JetTopLevelFunctionsFqnNameIndex.getInstance().get(childName(name), project, searchScope)
}
override fun getPropertyDeclarations(name: Name): Collection<JetProperty> {
return JetTopLevelPropertiesFqnNameIndex.getInstance().get(childName(name), project, searchScope)
}
override fun getAllDeclaredSubPackages(): Collection<FqName> {
return PackageIndexUtil.getSubPackageFqNames(fqName, searchScope, project)
}
override fun getPackageFiles(): Collection<JetFile> {
return PackageIndexUtil.findFilesWithExactPackage(fqName, searchScope, project)
}
private fun childName(name: Name): String {
return fqName.child(ResolveSessionUtils.safeNameForLazyResolve(name)).asString()
}
}
private val TOP_LEVEL_DECLARATION_INDICES: List<StringStubIndexExtension<out JetNamedDeclaration>> = listOf(
JetFullClassNameIndex.getInstance(),
JetTopLevelFunctionsFqnNameIndex.getInstance(),
JetTopLevelPropertiesFqnNameIndex.getInstance()
)
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.util;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.ShutDownTracker;
public final class ApplicationUtils {
private ApplicationUtils() {
}
public static void warnTimeConsuming(Logger logger) {
Application application = ApplicationManager.getApplication();
if (application.isUnitTestMode() || application.isHeadlessEnvironment() || ShutDownTracker.isShutdownHookRunning()) {
return;
}
if (!application.isDispatchThread()) {
return;
}
logger.warn("This operation is time consuming and must not be called on EDT.");
//noinspection CallToPrintStackTrace
new Throwable().printStackTrace();
}
}
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.util
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.tree.IElementType
import org.jetbrains.jet.lang.parsing.JetExpressionParsing
import java.util.HashMap
import org.jetbrains.jet.lang.parsing.JetExpressionParsing.Precedence.*
import org.jetbrains.jet.lang.psi.*
public object JetPsiPrecedences {
private val LOG = Logger.getInstance(javaClass<JetPsiPrecedences>())
private val precedence: Map<IElementType, Int>
{
val builder = HashMap<IElementType, Int>()
for ((i, record) in JetExpressionParsing.Precedence.values().withIndices()) {
for (elementType in record.getOperations().getTypes()) {
builder[elementType] = i
}
}
precedence = builder
}
public val PRECEDENCE_OF_ATOMIC_EXPRESSION: Int = -1
public val PRECEDENCE_OF_PREFIX_EXPRESSION: Int = PREFIX.ordinal()
public val PRECEDENCE_OF_POSTFIX_EXPRESSION: Int = POSTFIX.ordinal()
public fun getPrecedence(expression: JetExpression): Int {
return when (expression) {
is JetAnnotatedExpression,
is JetLabeledExpression,
is JetPrefixExpression -> PRECEDENCE_OF_PREFIX_EXPRESSION
is JetPostfixExpression -> PRECEDENCE_OF_POSTFIX_EXPRESSION
is JetOperationExpression -> {
val operation = expression.getOperationReference().getReferencedNameElementType()
val precedenceNumber = precedence[operation]
if (precedenceNumber == null) {
LOG.error("No precedence for operation: " + operation)
precedence.size()
}
else precedenceNumber
}
else -> PRECEDENCE_OF_ATOMIC_EXPRESSION
}
}
public fun isTighter(subject: Int, tighterThan: Int): Boolean {
return subject < tighterThan
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.versions;
import com.google.common.collect.ImmutableList;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
public class KotlinRuntimeLibraryCoreUtil {
@Nullable
public static PsiClass getKotlinRuntimeMarkerClass(@NotNull GlobalSearchScope scope) {
FqName kotlinPackageFqName = FqName.topLevel(Name.identifier("kotlin"));
String kotlinPackageClassFqName = PackageClassUtils.getPackageClassFqName(kotlinPackageFqName).asString();
ImmutableList<String> candidateClassNames = ImmutableList.of(
kotlinPackageClassFqName,
"kotlin.Unit",
// For older versions
"kotlin.namespace",
"jet.Unit"
);
for (String className : candidateClassNames) {
PsiClass psiClass = JavaPsiFacade.getInstance(scope.getProject()).findClass(className, scope);
if (psiClass != null) {
return psiClass;
}
}
return null;
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.vfilefinder;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.impl.file.impl.JavaFileManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.indexing.FileBasedIndex;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder;
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClassFinder;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.Collection;
public final class IDEVirtualFileFinder extends VirtualFileKotlinClassFinder implements VirtualFileFinder {
private static final Logger LOG = Logger.getInstance(IDEVirtualFileFinder.class);
@NotNull private final Project project;
public IDEVirtualFileFinder(@NotNull Project project) {
this.project = project;
}
@Nullable
@Override
public VirtualFile findVirtualFileWithHeader(@NotNull FqName className) {
Collection<VirtualFile> files =
FileBasedIndex.getInstance().getContainingFiles(KotlinClassFileIndex.KEY, className, GlobalSearchScope.allScope(project));
if (files.isEmpty()) {
return null;
}
if (files.size() > 1) {
LOG.warn("There are " + files.size() + " classes with same fqName: " + className + " found.");
}
return files.iterator().next();
}
@Override
public VirtualFile findVirtualFile(@NotNull String internalName) {
JavaFileManager fileFinder = ServiceManager.getService(project, JavaFileManager.class);
String qName = internalName.replace('/', '.');
PsiClass psiClass = fileFinder.findClass(qName, GlobalSearchScope.allScope(project));
if (psiClass == null) {
int dollarIndex = qName.indexOf('$');
assert dollarIndex > 0 : "Only inner classes could be found with this patch: " + internalName;
String newName = qName.substring(0, dollarIndex);
psiClass = fileFinder.findClass(newName, GlobalSearchScope.allScope(project));
if (psiClass != null) {
int i = qName.lastIndexOf('.');
return psiClass.getContainingFile().getVirtualFile().getParent().findChild(qName.substring(i + 1) + ".class");
}
}
if (psiClass != null) {
return psiClass.getContainingFile().getVirtualFile();
}
return null;
}
}
@@ -0,0 +1,121 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.vfilefinder;
import com.intellij.ide.highlighter.JavaClassFileType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.indexing.*;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
public final class KotlinClassFileIndex extends ScalarIndexExtension<FqName> {
private static final Logger LOG = Logger.getInstance(KotlinClassFileIndex.class);
private static final int VERSION = 2;
public static final ID<FqName, Void> KEY = ID.create(KotlinClassFileIndex.class.getCanonicalName());
private static final KeyDescriptor<FqName> KEY_DESCRIPTOR = new KeyDescriptor<FqName>() {
@Override
public void save(DataOutput out, FqName value) throws IOException {
out.writeUTF(value.asString());
}
@Override
public FqName read(DataInput in) throws IOException {
return new FqName(in.readUTF());
}
@Override
public int getHashCode(FqName value) {
return value.asString().hashCode();
}
@Override
public boolean isEqual(FqName val1, FqName val2) {
if (val1 == null) {
return val2 == null;
}
return val1.equals(val1);
}
};
private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() {
@Override
public boolean acceptInput(VirtualFile file) {
return file.getFileType() == JavaClassFileType.INSTANCE;
}
};
public static final DataIndexer<FqName, Void, FileContent> INDEXER = new DataIndexer<FqName, Void, FileContent>() {
@NotNull
@Override
public Map<FqName, Void> map(FileContent inputData) {
try {
KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(inputData.getFile());
if (kotlinClass != null && kotlinClass.getClassHeader().getKind() != KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) {
return Collections.singletonMap(kotlinClass.getClassName().getFqNameForClassNameWithoutDollars(), null);
}
}
catch (Throwable e) {
LOG.warn("Error while indexing file " + inputData.getFileName(), e);
}
return Collections.emptyMap();
}
};
@NotNull
@Override
public ID<FqName, Void> getName() {
return KEY;
}
@NotNull
@Override
public DataIndexer<FqName, Void, FileContent> getIndexer() {
return INDEXER;
}
@Override
public KeyDescriptor<FqName> getKeyDescriptor() {
return KEY_DESCRIPTOR;
}
@Override
public FileBasedIndex.InputFilter getInputFilter() {
return INPUT_FILTER;
}
@Override
public boolean dependsOnFileContent() {
return true;
}
@Override
public int getVersion() {
return VERSION;
}
}