Skip to content

Commit 16d548c

Browse files
author
miheevks
committed
Merge branch 'intellij-solidity-master'
# Conflicts: # gradle.properties # src/main/kotlin/me/serce/solidity/ide/highlighter.kt
2 parents b4b3b5e + b2cf6a4 commit 16d548c

File tree

25 files changed

+210
-27
lines changed

25 files changed

+210
-27
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*.ipr
66
*.iws
77
gen
8-
lib
8+
/lib
99
.sandbox
1010
.DS_Store
1111
/out/

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version=[2.3.10-TL-0.9-SNAPSHOT
1+
version=2.3.11-TL-0.9-SNAPSHOT
22
group=me.serce
33
kotlin_version=1.6.21
44
sentry_version=1.6.4

src/main/kotlin/me/serce/solidity/ide/actions/createFile.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class SolCreateFileAction : CreateFileFromTemplateAction(CAPTION, "", SolidityIc
2525
) {
2626
builder.setTitle(CAPTION)
2727
.addKind("Smart contract", SolidityIcons.FILE_ICON, SMART_CONTRACT_TEMPLATE)
28+
.addKind("Smart contract interface", SolidityIcons.FILE_ICON, "Solidity Contract Interface")
2829
.addKind("Solidity library", SolidityIcons.FILE_ICON, "Solidity Library")
2930
.setValidator(object : InputValidatorEx {
3031
override fun checkInput(inputString: String): Boolean {

src/main/kotlin/me/serce/solidity/ide/annotation/annotator.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ class SolidityAnnotator : Annotator {
2323
when (element) {
2424
is SolNumberType -> applyColor(holder, element, SolColor.TYPE)
2525
is SolElementaryTypeName -> applyColor(holder, element, SolColor.TYPE)
26+
is SolStateMutability -> if (element.text == "payable") {
27+
applyColor(holder, element, SolColor.KEYWORD)
28+
}
29+
is SolEnumValue -> applyColor(holder, element, SolColor.ENUM_VALUE)
2630
is SolMemberAccessExpression -> when(element.expression.firstChild.text) {
2731
"super" -> applyColor(holder, element.expression.firstChild, SolColor.KEYWORD)
2832
"msg", "block", "abi" -> applyColor(holder, element.expression.firstChild, SolColor.GLOBAL)
@@ -49,6 +53,7 @@ class SolidityAnnotator : Annotator {
4953
is SolStructDefinition -> element.identifier?.let { applyColor(holder, it, SolColor.STRUCT_NAME) }
5054
is SolEnumDefinition -> element.identifier?.let { applyColor(holder, it, SolColor.ENUM_NAME) }
5155
is SolEventDefinition -> element.identifier?.let { applyColor(holder, it, SolColor.EVENT_NAME) }
56+
is SolUserDefinedValueTypeDefinition -> element.identifier?.let { applyColor(holder, it, SolColor.USER_DEFINED_VALUE_TYPE) }
5257
is SolConstantVariableDeclaration -> applyColor(holder, element.identifier, SolColor.CONSTANT)
5358
is SolStateVariableDeclaration -> {
5459
if (element.mutationModifier?.textMatches("constant") == true) {
@@ -57,7 +62,17 @@ class SolidityAnnotator : Annotator {
5762
applyColor(holder, element.identifier, SolColor.STATE_VARIABLE)
5863
}
5964
}
60-
is SolFunctionDefinition -> element.identifier?.let { applyColor(holder, it, SolColor.FUNCTION_DECLARATION) }
65+
is SolFunctionDefinition -> {
66+
val identifier = element.identifier
67+
if (identifier !== null) {
68+
applyColor(holder, identifier, SolColor.FUNCTION_DECLARATION)
69+
} else {
70+
val firstChildNode = element.node.firstChildNode
71+
if (firstChildNode.text == "receive" || firstChildNode.text == "fallback") {
72+
applyColor(holder, firstChildNode.textRange, SolColor.RECEIVE_FALLBACK_DECLARATION)
73+
}
74+
}
75+
}
6176
is SolModifierDefinition -> element.identifier?.let { applyColor(holder, it, SolColor.FUNCTION_DECLARATION) }
6277
is SolModifierInvocation -> applyColor(holder, element.varLiteral.identifier, SolColor.FUNCTION_CALL)
6378
is SolUserDefinedTypeName -> {
@@ -71,10 +86,17 @@ class SolidityAnnotator : Annotator {
7186
is SolFunctionCallElement -> when(element.firstChild.text) {
7287
"keccak256" -> applyColor(holder, element.firstChild, SolColor.GLOBAL_FUNCTION_CALL)
7388
"require" -> applyColor(holder, element.firstChild, SolColor.KEYWORD)
89+
"assert" -> applyColor(holder, element.firstChild, SolColor.KEYWORD)
7490
else -> when(SolResolver.resolveTypeNameUsingImports(element).firstOrNull()) {
7591
is SolErrorDefinition -> applyColor(holder, element.referenceNameElement, SolColor.ERROR_NAME)
7692
is SolEventDefinition -> applyColor(holder, element.referenceNameElement, SolColor.EVENT_NAME)
77-
else -> applyColor(holder, element.referenceNameElement, SolColor.FUNCTION_CALL)
93+
else -> element.firstChild.let {
94+
if (it is SolPrimaryExpression && SolResolver.resolveTypeNameUsingImports(element.firstChild).filterIsInstance<SolStructDefinition>().isNotEmpty()) {
95+
applyColor(holder, element.referenceNameElement, SolColor.STRUCT_NAME)
96+
} else {
97+
applyColor(holder, element.referenceNameElement, SolColor.FUNCTION_CALL)
98+
}
99+
}
78100
}
79101
}
80102
}

src/main/kotlin/me/serce/solidity/ide/colors/SolColor.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ enum class SolColor(humanName: String, default: TextAttributesKey) {
1313
ERROR_NAME("Types//Error name", Defaults.CLASS_NAME),
1414
EVENT_NAME("Types//Event name", Defaults.CLASS_NAME),
1515
ENUM_NAME("Types//Enum name", Defaults.CLASS_NAME),
16+
ENUM_VALUE("Types//Enum value", Defaults.STATIC_FIELD),
1617
TYPE("Types//Value type", Defaults.KEYWORD),
1718
USER_DEFINED_VALUE_TYPE("Types//User-defined value type", Defaults.CLASS_NAME),
1819

@@ -21,6 +22,7 @@ enum class SolColor(humanName: String, default: TextAttributesKey) {
2122
STATE_VARIABLE("Identifiers//State variable", Defaults.INSTANCE_FIELD),
2223

2324
FUNCTION_DECLARATION("Functions//Function declaration", Defaults.FUNCTION_DECLARATION),
25+
RECEIVE_FALLBACK_DECLARATION("Functions//Receive/Fallback declaration", Defaults.STATIC_METHOD),
2426
FUNCTION_CALL("Functions//Function call", Defaults.FUNCTION_CALL),
2527
GLOBAL_FUNCTION_CALL("Functions//Global function call", Defaults.GLOBAL_VARIABLE),
2628

src/main/kotlin/me/serce/solidity/ide/highlighter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ object SolHighlighter : SyntaxHighlighterBase() {
5656
IF, ELSE, FOR, WHILE, DO, BREAK, CONTINUE, THROW, USING, RETURN, RETURNS,
5757
MAPPING, EVENT, /*ERROR,*/ ANONYMOUS, MODIFIER, ASSEMBLY,
5858
VAR, STORAGE, MEMORY, WEI, ETHER, GWEI, SZABO, FINNEY, SECONDS, MINUTES, HOURS,
59-
DAYS, WEEKS, YEARS, TYPE, VIRTUAL, OVERRIDE,
59+
DAYS, WEEKS, YEARS, TYPE, VIRTUAL, OVERRIDE, IMMUTABLE, INDEXED,
6060
NANO, NANOTON, NTON, TON, MICRO,
6161
MICROTON, MILLI, MILLITON, KILOTON, KTON,
6262
MEGATON, MTON, GIGATON, GTON,

src/main/kotlin/me/serce/solidity/lang/resolve/engine.kt

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ object SolResolver {
2424
val result = if (element is SolFunctionCallElement) {
2525
resolveError(element) +
2626
resolveEvent(element) +
27-
resolveContractUsingImports(element, element.containingFile, true) +
27+
resolveContract(element) +
2828
resolveEnum(element) +
2929
resolveUserDefinedValueType(element)
3030
} else {
31-
resolveContractUsingImports(element, element.containingFile, true) +
31+
resolveContract(element) +
3232
resolveEnum(element) +
3333
resolveStruct(element) +
3434
resolveUserDefinedValueType(element)
@@ -39,17 +39,18 @@ object SolResolver {
3939
/**
4040
* @param withAliases aliases are not recursive, so count them only at the first level of recursion
4141
*/
42-
private fun resolveContractUsingImports(
42+
private fun <T: SolNamedElement>resolveUsingImports(
43+
target: Class<T>,
4344
element: PsiElement,
4445
file: PsiFile,
45-
withAliases: Boolean
46-
): Set<SolContractDefinition> =
47-
RecursionManager.doPreventingRecursion(ResolveContractKey(element.nameOrText, file), true) {
46+
withAliases: Boolean,
47+
): Set<T> =
48+
RecursionManager.doPreventingRecursion(ResolveUsingImportsKey(element.nameOrText, file), true) {
4849
if (element is SolUserDefinedTypeName && element.findIdentifiers().size > 1) {
4950
emptySet()
5051
} else {
5152
val inFile = file.children
52-
.filterIsInstance<SolContractDefinition>()
53+
.filterIsInstance(target)
5354
.filter { it.name == element.nameOrText }
5455

5556
val resolvedViaAlias = when (withAliases) {
@@ -64,36 +65,38 @@ object SolResolver {
6465
}
6566
}
6667
}.flatMap { (alias, resolvedFile) ->
67-
resolveContractUsingImports(alias, resolvedFile.containingFile, false)
68+
resolveUsingImports(target, alias, resolvedFile.containingFile, false)
6869
}
6970
else -> emptyList()
7071
}
7172

7273
val imported = file.children
7374
.filterIsInstance<SolImportDirective>()
7475
.mapNotNull { nullIfError { it.importPath?.reference?.resolve()?.containingFile } }
75-
.flatMap { resolveContractUsingImports(element, it, false) }
76+
.flatMap { resolveUsingImports(target, element, it, false) }
7677

7778
(inFile + resolvedViaAlias + imported).toSet()
7879
}
7980
} ?: emptySet()
8081

82+
private fun resolveContract(element: PsiElement): Set<SolContractDefinition> =
83+
resolveUsingImports(SolContractDefinition::class.java, element, element.containingFile, true)
8184
private fun resolveEnum(element: PsiElement): Set<SolNamedElement> =
82-
resolveInFile<SolEnumDefinition>(element) + resolveInnerType<SolEnumDefinition>(element) { it.enumDefinitionList }
85+
resolveInnerType<SolEnumDefinition>(element) { it.enumDefinitionList } + resolveUsingImports(SolEnumDefinition::class.java, element, element.containingFile, true)
8386

8487
private fun resolveStruct(element: PsiElement): Set<SolNamedElement> =
85-
resolveInFile<SolStructDefinition>(element) + resolveInnerType<SolStructDefinition>(element) { it.structDefinitionList }
88+
resolveInnerType<SolStructDefinition>(element) { it.structDefinitionList } + resolveUsingImports(SolStructDefinition::class.java, element, element.containingFile, true)
8689

8790
private fun resolveUserDefinedValueType(element: PsiElement): Set<SolNamedElement> =
88-
resolveInFile<SolUserDefinedValueTypeDefinition>(element) + resolveInnerType<SolUserDefinedValueTypeDefinition>(
91+
resolveInnerType<SolUserDefinedValueTypeDefinition>(
8992
element,
90-
{ it.userDefinedValueTypeDefinitionList })
93+
{ it.userDefinedValueTypeDefinitionList }) + resolveUsingImports(SolUserDefinedValueTypeDefinition::class.java, element, element.containingFile, true)
9194

9295
private fun resolveEvent(element: PsiElement): Set<SolNamedElement> =
9396
resolveInnerType<SolEventDefinition>(element) { it.eventDefinitionList }
9497

9598
private fun resolveError(element: PsiElement): Set<SolNamedElement> =
96-
resolveInnerType<SolErrorDefinition>(element) { it.errorDefinitionList }
99+
resolveInnerType<SolErrorDefinition>(element) { it.errorDefinitionList } + resolveUsingImports(SolErrorDefinition::class.java, element, element.containingFile, true)
97100

98101
private inline fun <reified T : SolNamedElement> resolveInFile(element: PsiElement) : Set<T> {
99102
return element.parentOfType<SolidityFile>()
@@ -343,7 +346,7 @@ object SolResolver {
343346
}
344347
}
345348

346-
data class ResolveContractKey(val name: String?, val file: PsiFile)
349+
data class ResolveUsingImportsKey(val name: String?, val file: PsiFile)
347350

348351
private fun <T> Sequence<T>.takeWhileInclusive(pred: (T) -> Boolean): Sequence<T> {
349352
var shouldContinue = true

src/main/kotlin/me/serce/solidity/lang/resolve/ref/SolImportPathReference.kt

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,50 @@ class SolImportPathReference(element: SolImportPathElement) : SolReferenceBase<S
4545
}
4646
}
4747

48-
// default lib located at: forge-std/Test.sol => lib/forge-std/src/Test.sol
49-
private fun findFoundryImportFile(file: VirtualFile, path: String): VirtualFile? {
48+
// apply foundry remappings to import path
49+
private fun applyRemappings(remappings: ArrayList<Pair<String,String>>, path: String):String {
50+
var output = path;
51+
remappings.forEach { (prefix, target) ->
52+
if (path.contains(prefix)) {
53+
output = path.replace(prefix, target)
54+
return output
55+
}
56+
}
57+
return output;
58+
}
59+
60+
private fun foundryDefaultFallback(file: VirtualFile, path: String): VirtualFile? {
5061
val count = Paths.get(path).nameCount;
51-
if (count < 2) {
62+
if (count<2) {
5263
return null;
5364
}
54-
val libName = Paths.get(path).subpath(0, 1).toString();
55-
val libFile = Paths.get(path).subpath(1, count).toString();
65+
val libName = Paths.get(path).subpath(0,1).toString();
66+
val libFile = Paths.get(path).subpath(1,count).toString();
5667
val test = file.findFileByRelativePath("lib/$libName/src/$libFile");
68+
return test;
69+
}
70+
71+
// default lib located at: forge-std/Test.sol => lib/forge-std/src/Test.sol
72+
private fun findFoundryImportFile(file: VirtualFile, path: String): VirtualFile? {
73+
val testRemappingFile = file.findFileByRelativePath("remappings.txt");
74+
val remappings = arrayListOf<Pair<String, String>>();
75+
if (testRemappingFile != null) {
76+
val mappingsContents = testRemappingFile.contentsToByteArray().toString(Charsets.UTF_8).split("[\r\n]+".toRegex());
77+
mappingsContents.forEach { mapping ->
78+
val splitMapping = mapping.split("=")
79+
if (splitMapping.size == 2) {
80+
remappings.add(Pair(splitMapping[0].trim(),splitMapping[1].trim()))
81+
}
82+
}
83+
}
84+
85+
val remappedPath = applyRemappings(remappings, path);
86+
val testRemappedPath = file.findFileByRelativePath(remappedPath);
87+
val testFoundryFallback = foundryDefaultFallback(file, path);
88+
5789
return when {
58-
test != null -> test
90+
testRemappedPath != null -> testRemappedPath
91+
testFoundryFallback != null -> testFoundryFallback
5992
file.parent != null -> findFoundryImportFile(file.parent, path)
6093
else -> null
6194
}

src/main/kotlin/me/serce/solidity/lang/resolve/ref/refs.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ class SolFunctionCallReference(element: SolFunctionCallExpression) : SolReferenc
9393
}
9494

9595
fun resolveFunctionCall(): Collection<SolCallable> {
96+
if (element.parent is SolRevertStatement) {
97+
return SolResolver.resolveTypeNameUsingImports(element).filterIsInstance<SolErrorDefinition>()
98+
}
99+
if (element.firstChild is SolPrimaryExpression) {
100+
val structs = SolResolver.resolveTypeNameUsingImports(element.firstChild).filterIsInstance<SolStructDefinition>()
101+
if (structs.isNotEmpty()) {
102+
return structs
103+
}
104+
}
96105
val resolved: Collection<SolCallable> = when (val expr = element.expression) {
97106
is SolPrimaryExpression -> {
98107
val regular = expr.varLiteral?.let { SolResolver.resolveVarLiteral(it) }

src/main/kotlin/me/serce/solidity/lang/types/inference.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ private fun getSolTypeFromUserDefinedTypeName(type: SolUserDefinedTypeName): Sol
7373
is SolContractDefinition -> SolContract(it)
7474
is SolStructDefinition -> SolStruct(it)
7575
is SolEnumDefinition -> SolEnum(it)
76+
is SolUserDefinedValueTypeDefinition -> getSolType(it.elementaryTypeName)
7677
else -> null
7778
}
7879
}

0 commit comments

Comments
 (0)