checkers, annotators and dependencies moved to idea-analysis module
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
+34
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
+191
@@ -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) {
|
||||
}
|
||||
}
|
||||
+214
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -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();
|
||||
}
|
||||
}
|
||||
+37
@@ -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()
|
||||
}
|
||||
+53
@@ -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;
|
||||
}
|
||||
}
|
||||
+53
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
+46
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
+29
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+283
@@ -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);
|
||||
}
|
||||
}
|
||||
+50
@@ -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);
|
||||
}
|
||||
}
|
||||
+119
@@ -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;
|
||||
}
|
||||
}
|
||||
+240
@@ -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);
|
||||
}
|
||||
}
|
||||
+89
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -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();
|
||||
}
|
||||
}
|
||||
+30
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
+112
@@ -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)
|
||||
}
|
||||
+36
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+97
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+105
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+111
@@ -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 = " "
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
+34
@@ -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())
|
||||
}
|
||||
}
|
||||
+61
@@ -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()
|
||||
}
|
||||
+212
@@ -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)
|
||||
}
|
||||
}
|
||||
+127
@@ -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
|
||||
}
|
||||
+195
@@ -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());
|
||||
}
|
||||
}
|
||||
+29
@@ -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"
|
||||
+193
@@ -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);
|
||||
}
|
||||
}
|
||||
+491
@@ -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;
|
||||
}
|
||||
}
|
||||
+29
@@ -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);
|
||||
}
|
||||
+162
@@ -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() {}
|
||||
}
|
||||
+262
@@ -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));
|
||||
}
|
||||
}
|
||||
+49
@@ -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));
|
||||
}
|
||||
}
|
||||
+49
@@ -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));
|
||||
}
|
||||
}
|
||||
+40
@@ -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;
|
||||
}
|
||||
}
|
||||
+54
@@ -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));
|
||||
}
|
||||
}
|
||||
+49
@@ -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));
|
||||
}
|
||||
}
|
||||
+49
@@ -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));
|
||||
}
|
||||
}
|
||||
+51
@@ -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());
|
||||
}
|
||||
}
|
||||
+34
@@ -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) }
|
||||
}
|
||||
+59
@@ -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)
|
||||
}
|
||||
}
|
||||
+38
@@ -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)
|
||||
}
|
||||
}
|
||||
+78
@@ -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
|
||||
}
|
||||
}
|
||||
+51
@@ -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;
|
||||
}
|
||||
}
|
||||
+121
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user