Skip to content

Commit d0583bc

Browse files
committed
Merge branch 'main' into release/2.x
2 parents 23be433 + 7683220 commit d0583bc

File tree

7 files changed

+152
-49
lines changed

7 files changed

+152
-49
lines changed

.clang-tidy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Checks: >
88
performance-*,
99
portability-*,
1010
readability-*,
11+
-llvm-else-after-return,
12+
-readability-else-after-return,
1113
-readability-use-anyofallof,
1214
-misc-const-correctness,
1315
-misc-unused-parameters,

libnixf/src/Sema/VariableLookup.cpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,41 +76,44 @@ void VariableLookupAnalysis::emitEnvLivenessWarning(
7676

7777
void VariableLookupAnalysis::lookupVar(const ExprVar &Var,
7878
const std::shared_ptr<EnvNode> &Env) {
79-
const std::string &Name = Var.id().name();
80-
81-
bool EnclosedWith = false; // If there is a "With" enclosed this var name.
82-
EnvNode *WithEnv = nullptr;
83-
EnvNode *CurEnv = Env.get();
79+
const auto &Name = Var.id().name();
80+
const auto *CurEnv = Env.get();
8481
std::shared_ptr<Definition> Def;
82+
std::vector<const EnvNode *> WithEnvs;
8583
for (; CurEnv; CurEnv = CurEnv->parent()) {
8684
if (CurEnv->defs().contains(Name)) {
8785
Def = CurEnv->defs().at(Name);
8886
break;
8987
}
90-
// Find the most nested `with` expression, and set uses.
91-
if (CurEnv->isWith() && !EnclosedWith) {
92-
EnclosedWith = true;
93-
WithEnv = CurEnv;
88+
// Find all nested "with" expression, variables potentially come from those.
89+
// For example
90+
// with lib;
91+
// with builtins;
92+
// generators <--- this variable may come from "lib" | "builtins"
93+
//
94+
// We cannot determine where it precisely come from, thus mark all Envs
95+
// alive.
96+
if (CurEnv->isWith()) {
97+
WithEnvs.emplace_back(CurEnv);
9498
}
9599
}
96100

97101
if (Def) {
98102
Def->usedBy(Var);
99103
Results.insert({&Var, LookupResult{LookupResultKind::Defined, Def}});
100-
return;
101-
}
102-
if (EnclosedWith) {
103-
Def = WithDefs.at(WithEnv->syntax());
104-
Def->usedBy(Var);
104+
} else if (!WithEnvs.empty()) { // comes from enclosed "with" expressions.
105+
for (const auto *WithEnv : WithEnvs) {
106+
Def = WithDefs.at(WithEnv->syntax());
107+
Def->usedBy(Var);
108+
}
105109
Results.insert({&Var, LookupResult{LookupResultKind::FromWith, Def}});
106-
return;
110+
} else {
111+
// Otherwise, this variable is undefined.
112+
Results.insert({&Var, LookupResult{LookupResultKind::Undefined, nullptr}});
113+
Diagnostic &Diag =
114+
Diags.emplace_back(Diagnostic::DK_UndefinedVariable, Var.range());
115+
Diag << Var.id().name();
107116
}
108-
109-
// Otherwise, this variable is undefined.
110-
Results.insert({&Var, LookupResult{LookupResultKind::Undefined, nullptr}});
111-
Diagnostic &Diag =
112-
Diags.emplace_back(Diagnostic::DK_UndefinedVariable, Var.range());
113-
Diag << Var.id().name();
114117
}
115118

116119
void VariableLookupAnalysis::dfs(const ExprLambda &Lambda,

libnixf/test/Sema/VariableLookup.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,4 +324,18 @@ in 1
324324
ASSERT_EQ(Diags.size(), 1);
325325
}
326326

327+
TEST_F(VLATest, Issue606_NestedWith) {
328+
const char *Src = R"(
329+
with builtins;
330+
with builtins;
331+
concatLists
332+
)";
333+
334+
std::shared_ptr<Node> AST = parse(Src, Diags);
335+
VariableLookupAnalysis VLA(Diags);
336+
VLA.runOnAST(*AST);
337+
338+
ASSERT_EQ(Diags.size(), 0);
339+
}
340+
327341
} // namespace

nixd/docs/features.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ Screenshots:
3232

3333
### Semantic Tokens
3434

35+
> [!WARNING]
36+
> This feature is experimental and not enabled by default.
37+
3538
[nixd language server](https://github.com/nix-community/nixd) tries to make some tokens looks different by sending your editor some integers.
3639
However, types in nix language is pretty different from standard LSP types.
3740
So, as a result, attrnames, selection, variables are colored as different integers,
3841
but the colors may, or may not rendered properly in your editor.
3942

4043
> [!TIP]
41-
> `--semantic-tokens=false` to disable the feature.
44+
> `--semantic-tokens=true` to enable the feature.
4245
4346
#### Attribute name coloring
4447

nixd/lib/Controller/LifeTime.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ opt<std::string> DefaultNixOSOptionsExpr{
3838

3939
opt<bool> EnableSemanticTokens{"semantic-tokens",
4040
desc("Enable/Disable semantic tokens"),
41-
init(true), cat(NixdCategory)};
41+
init(false), cat(NixdCategory)};
4242

4343
// Here we try to wrap nixpkgs, nixos options in a single emtpy attrset in test.
4444
std::string getDefaultNixpkgsExpr() {

nixd/tools/nixd/test/initialize.md

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,32 +49,6 @@ CHECK-NEXT: "referencesProvider": true,
4949
CHECK-NEXT: "renameProvider": {
5050
CHECK-NEXT: "prepareProvider": true
5151
CHECK-NEXT: },
52-
CHECK-NEXT: "semanticTokensProvider": {
53-
CHECK-NEXT: "full": true,
54-
CHECK-NEXT: "legend": {
55-
CHECK-NEXT: "tokenModifiers": [
56-
CHECK-NEXT: "static",
57-
CHECK-NEXT: "abstract",
58-
CHECK-NEXT: "async"
59-
CHECK-NEXT: ],
60-
CHECK-NEXT: "tokenTypes": [
61-
CHECK-NEXT: "function",
62-
CHECK-NEXT: "string",
63-
CHECK-NEXT: "number",
64-
CHECK-NEXT: "type",
65-
CHECK-NEXT: "keyword",
66-
CHECK-NEXT: "variable",
67-
CHECK-NEXT: "interface",
68-
CHECK-NEXT: "variable",
69-
CHECK-NEXT: "regexp",
70-
CHECK-NEXT: "macro",
71-
CHECK-NEXT: "method",
72-
CHECK-NEXT: "regexp",
73-
CHECK-NEXT: "regexp"
74-
CHECK-NEXT: ]
75-
CHECK-NEXT: },
76-
CHECK-NEXT: "range": false
77-
CHECK-NEXT: },
7852
CHECK-NEXT: "textDocumentSync": {
7953
CHECK-NEXT: "change": 2,
8054
CHECK-NEXT: "openClose": true,
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# RUN: nixd --lit-test --semantic-tokens=true < %s | FileCheck %s
2+
3+
Check basic handshake with the server, i.e. "initialize"
4+
5+
<-- initialize(0)
6+
7+
```json
8+
{
9+
"jsonrpc":"2.0",
10+
"id":0,
11+
"method":"initialize",
12+
"params":{
13+
"processId":123,
14+
"rootPath":"",
15+
"capabilities":{ },
16+
"trace":"off"
17+
}
18+
}
19+
```
20+
21+
<-- reply:initialize(0)
22+
23+
```
24+
CHECK: {
25+
CHECK-NEXT: "id": 0,
26+
CHECK-NEXT: "jsonrpc": "2.0",
27+
CHECK-NEXT: "result": {
28+
CHECK-NEXT: "capabilities": {
29+
CHECK-NEXT: "codeActionProvider": {
30+
CHECK-NEXT: "codeActionKinds": [
31+
CHECK-NEXT: "quickfix"
32+
CHECK-NEXT: ],
33+
CHECK-NEXT: "resolveProvider": false
34+
CHECK-NEXT: },
35+
CHECK-NEXT: "completionProvider": {
36+
CHECK-NEXT: "resolveProvider": true,
37+
CHECK-NEXT: "triggerCharacters": [
38+
CHECK-NEXT: "."
39+
CHECK-NEXT: ]
40+
CHECK-NEXT: },
41+
CHECK-NEXT: "definitionProvider": true,
42+
CHECK-NEXT: "documentFormattingProvider": true,
43+
CHECK-NEXT: "documentHighlightProvider": true,
44+
CHECK-NEXT: "documentLinkProvider": {},
45+
CHECK-NEXT: "documentSymbolProvider": true,
46+
CHECK-NEXT: "hoverProvider": true,
47+
CHECK-NEXT: "inlayHintProvider": true,
48+
CHECK-NEXT: "referencesProvider": true,
49+
CHECK-NEXT: "renameProvider": {
50+
CHECK-NEXT: "prepareProvider": true
51+
CHECK-NEXT: },
52+
CHECK-NEXT: "semanticTokensProvider": {
53+
CHECK-NEXT: "full": true,
54+
CHECK-NEXT: "legend": {
55+
CHECK-NEXT: "tokenModifiers": [
56+
CHECK-NEXT: "static",
57+
CHECK-NEXT: "abstract",
58+
CHECK-NEXT: "async"
59+
CHECK-NEXT: ],
60+
CHECK-NEXT: "tokenTypes": [
61+
CHECK-NEXT: "function",
62+
CHECK-NEXT: "string",
63+
CHECK-NEXT: "number",
64+
CHECK-NEXT: "type",
65+
CHECK-NEXT: "keyword",
66+
CHECK-NEXT: "variable",
67+
CHECK-NEXT: "interface",
68+
CHECK-NEXT: "variable",
69+
CHECK-NEXT: "regexp",
70+
CHECK-NEXT: "macro",
71+
CHECK-NEXT: "method",
72+
CHECK-NEXT: "regexp",
73+
CHECK-NEXT: "regexp"
74+
CHECK-NEXT: ]
75+
CHECK-NEXT: },
76+
CHECK-NEXT: "range": false
77+
CHECK-NEXT: },
78+
CHECK-NEXT: "textDocumentSync": {
79+
CHECK-NEXT: "change": 2,
80+
CHECK-NEXT: "openClose": true,
81+
CHECK-NEXT: "save": true
82+
CHECK-NEXT: }
83+
CHECK-NEXT: }
84+
CHECK-NEXT: "serverInfo": {
85+
CHECK-NEXT: "name": "nixd",
86+
CHECK-NEXT: "version": {{.*}}
87+
CHECK-NEXT: }
88+
CHECK-NEXT: }
89+
CHECK-NEXT: }
90+
```
91+
92+
<-- initialized
93+
94+
```json
95+
{
96+
"jsonrpc":"2.0",
97+
"method":"initialized",
98+
"params":{
99+
100+
}
101+
}
102+
```
103+
104+
105+
```json
106+
{"jsonrpc":"2.0","method":"exit"}
107+
```

0 commit comments

Comments
 (0)