Skip to content

Commit 9ea824c

Browse files
committed
[GR-29883] Remove context from RubyWarnings
PullRequest: truffleruby/2485
2 parents 24571a4 + 7c8f3d5 commit 9ea824c

15 files changed

+321
-92
lines changed

spec/tags/core/kernel/eval_tags.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ fails:Kernel#eval unwinds through a Proc-style closure and returns from a lambda
44
slow:Kernel#eval raises a LocalJumpError if there is no lambda-style closure in the chain
55
slow:Kernel#eval does not share locals across eval scopes
66
fails(cannot store constant with name in binary encoding):Kernel#eval with a magic encoding comment ignores the magic encoding comment if it is after a frozen_string_literal magic comment
7+
fails:Kernel#eval with a magic encoding comment ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fails(GR-30031):Numbered parameters warns when numbered parameter is overwritten with local variable

src/main/java/org/truffleruby/aot/ParserCache.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
import java.io.IOException;
1313
import java.util.HashMap;
1414
import java.util.Map;
15+
import java.util.stream.Collectors;
1516

1617
import com.oracle.truffle.api.CompilerDirectives;
1718
import org.truffleruby.core.CoreLibrary;
1819
import org.truffleruby.language.loader.ResourceLoader;
20+
import org.truffleruby.parser.RubyDeferredWarnings;
1921
import org.truffleruby.parser.RubySource;
2022
import org.truffleruby.parser.TranslatorDriver;
2123
import org.truffleruby.parser.ast.RootParseNode;
@@ -59,8 +61,15 @@ private static RubySource loadSource(String feature) {
5961
private static RootParseNode parse(RubySource source) {
6062
final StaticScope staticScope = new StaticScope(StaticScope.Type.LOCAL, null);
6163
final ParserConfiguration parserConfiguration = new ParserConfiguration(null, false, true, false);
62-
63-
return TranslatorDriver.parseToJRubyAST(null, source, staticScope, parserConfiguration);
64+
RubyDeferredWarnings rubyWarnings = new RubyDeferredWarnings();
65+
RootParseNode rootParseNode = TranslatorDriver
66+
.parseToJRubyAST(null, source, staticScope, parserConfiguration, rubyWarnings);
67+
if (!rubyWarnings.warnings.isEmpty()) {
68+
throw new RuntimeException("Core files should not emit warnings: " + String.join(
69+
"\n",
70+
rubyWarnings.warnings.stream().map(w -> w.getWarningMessage()).collect(Collectors.toList())));
71+
}
72+
return rootParseNode;
6473
}
6574

6675
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.core.regexp;
11+
12+
import org.joni.WarnCallback;
13+
import org.truffleruby.parser.RubyDeferredWarnings;
14+
15+
public class RegexWarnDeferredCallback implements WarnCallback {
16+
17+
private final RubyDeferredWarnings warnings;
18+
19+
public RegexWarnDeferredCallback(RubyDeferredWarnings warnings) {
20+
this.warnings = warnings;
21+
}
22+
23+
@Override
24+
public void warn(String message) {
25+
warnings.warn(message);
26+
}
27+
28+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (c) 2021, 2021 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.language;
11+
12+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
13+
import com.oracle.truffle.api.frame.VirtualFrame;
14+
import org.jcodings.specific.UTF8Encoding;
15+
import org.truffleruby.RubyContext;
16+
import org.truffleruby.core.rope.Rope;
17+
import org.truffleruby.core.string.RubyString;
18+
import org.truffleruby.core.string.StringOperations;
19+
import org.truffleruby.language.control.RaiseException;
20+
import org.truffleruby.parser.RubyDeferredWarnings;
21+
22+
import java.io.IOException;
23+
import java.nio.charset.StandardCharsets;
24+
25+
public class EmitWarningsNode extends RubyContextSourceNode {
26+
27+
public final RubyDeferredWarnings warnings;
28+
29+
public EmitWarningsNode(RubyDeferredWarnings warnings) {
30+
this.warnings = warnings;
31+
}
32+
33+
@Override
34+
public Object execute(VirtualFrame frame) {
35+
final RubyContext context = getContext();
36+
printWarnings(context);
37+
return nil;
38+
}
39+
40+
public void printWarnings(RubyContext context) {
41+
printWarnings(context, warnings);
42+
}
43+
44+
@TruffleBoundary
45+
public static void printWarnings(RubyContext context, RubyDeferredWarnings warnings) {
46+
if (context == null) {
47+
for (RubyDeferredWarnings.WarningMessage warningMessage : warnings.warnings) {
48+
System.err.println(warningMessage.getWarningMessage());
49+
}
50+
} else {
51+
boolean isVerbose = context.getCoreLibrary().isVerbose();
52+
boolean warningsEnabled = context.getCoreLibrary().warningsEnabled();
53+
for (RubyDeferredWarnings.WarningMessage warningMessage : warnings.warnings) {
54+
if (warningMessage.verbosity == RubyDeferredWarnings.Verbosity.VERBOSE) {
55+
if (isVerbose) {
56+
printWarning(context, warningMessage.getWarningMessage());
57+
}
58+
} else {
59+
if (warningsEnabled) {
60+
printWarning(context, warningMessage.getWarningMessage());
61+
}
62+
}
63+
}
64+
}
65+
}
66+
67+
private static void printWarning(RubyContext context, String message) {
68+
if (context.getCoreLibrary().isLoaded()) {
69+
final Object warning = context.getCoreLibrary().warningModule;
70+
final Rope messageRope = StringOperations.encodeRope(message, UTF8Encoding.INSTANCE);
71+
final RubyString messageString = StringOperations
72+
.createString(context, context.getLanguageSlow(), messageRope);
73+
RubyContext.send(warning, "warn", messageString);
74+
} else {
75+
try {
76+
context.getEnvErrStream().write(message.getBytes(StandardCharsets.UTF_8));
77+
} catch (IOException e) {
78+
throw new RaiseException(context, context.getCoreExceptions().ioError(e, null));
79+
}
80+
}
81+
}
82+
}

src/main/java/org/truffleruby/language/TruffleBootNodes.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.stream.Collectors;
1616

1717
import com.oracle.truffle.api.library.CachedLibrary;
18+
import com.oracle.truffle.api.nodes.NodeUtil;
1819
import org.graalvm.options.OptionDescriptor;
1920
import org.jcodings.specific.UTF8Encoding;
2021
import org.truffleruby.RubyContext;
@@ -288,8 +289,14 @@ public abstract static class InnerCheckSyntaxNode extends CoreMethodArrayArgumen
288289
@TruffleBoundary
289290
@Specialization
290291
protected Object innerCheckSyntax(RubySource source) {
291-
getContext().getCodeLoader().parse(source, ParserContext.TOP_LEVEL, null, null, true, null);
292-
292+
RubyContext context = getContext();
293+
RubyRootNode rubyRootNode = context
294+
.getCodeLoader()
295+
.parse(source, ParserContext.TOP_LEVEL, null, null, true, null);
296+
EmitWarningsNode emitWarningsNode = NodeUtil.findFirstNodeInstance(rubyRootNode, EmitWarningsNode.class);
297+
if (emitWarningsNode != null) {
298+
emitWarningsNode.printWarnings(context);
299+
}
293300
return nil;
294301
}
295302

src/main/java/org/truffleruby/parser/BodyTranslator.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
import org.truffleruby.core.regexp.EncodingCache;
5050
import org.truffleruby.core.regexp.InterpolatedRegexpNode;
5151
import org.truffleruby.core.regexp.MatchDataNodes.GetIndexNode;
52-
import org.truffleruby.core.regexp.RegexWarnCallback;
52+
import org.truffleruby.core.regexp.RegexWarnDeferredCallback;
5353
import org.truffleruby.core.regexp.RegexpNodes;
5454
import org.truffleruby.core.regexp.RegexpOptions;
5555
import org.truffleruby.core.regexp.RubyRegexp;
@@ -281,6 +281,7 @@ public class BodyTranslator extends Translator {
281281

282282
protected final BodyTranslator parent;
283283
protected final TranslatorEnvironment environment;
284+
private final RubyDeferredWarnings rubyWarnings;
284285

285286
public boolean translatingForStatement = false;
286287
private boolean translatingNextExpression = false;
@@ -293,10 +294,12 @@ public BodyTranslator(
293294
TranslatorEnvironment environment,
294295
Source source,
295296
ParserContext parserContext,
296-
Node currentNode) {
297+
Node currentNode,
298+
RubyDeferredWarnings rubyWarnings) {
297299
super(context, source, parserContext, currentNode);
298300
this.parent = parent;
299301
this.environment = environment;
302+
this.rubyWarnings = rubyWarnings;
300303
}
301304

302305
private static RubyNode[] createArray(int size) {
@@ -1033,7 +1036,8 @@ private RubyNode openModule(SourceIndexLength sourceSection, RubyNode defineOrGe
10331036
newEnvironment,
10341037
source,
10351038
parserContext,
1036-
currentNode);
1039+
currentNode,
1040+
rubyWarnings);
10371041

10381042
final ModuleBodyDefinitionNode definition = moduleTranslator
10391043
.compileClassNode(sourceSection, bodyNode, type);
@@ -1485,7 +1489,8 @@ protected RubyNode translateMethodDefinition(SourceIndexLength sourceSection, Ru
14851489
parserContext,
14861490
currentNode,
14871491
argsNode,
1488-
null);
1492+
null,
1493+
rubyWarnings);
14891494

14901495
return withSourceSection(sourceSection, new LiteralMethodDefinitionNode(
14911496
moduleNode,
@@ -1999,7 +2004,8 @@ private RubyNode translateBlockLikeNode(IterParseNode node, boolean isLambda) {
19992004
parserContext,
20002005
currentNode,
20012006
argsNode,
2002-
currentCallMethodName);
2007+
currentCallMethodName,
2008+
rubyWarnings);
20032009

20042010
if (isProc) {
20052011
methodCompiler.translatingForStatement = translatingForStatement;
@@ -2117,7 +2123,7 @@ public RubyNode visitMatch2Node(Match2ParseNode node) {
21172123
regexpNode.getOptions().toOptions(),
21182124
regexpNode.getEncoding(),
21192125
Syntax.RUBY,
2120-
new RegexWarnCallback(context));
2126+
new RegexWarnDeferredCallback(rubyWarnings));
21212127
final int numberOfNames = regex.numberOfNames();
21222128

21232129
if (numberOfNames > 0) {

src/main/java/org/truffleruby/parser/MethodTranslator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ public MethodTranslator(
8484
ParserContext parserContext,
8585
Node currentNode,
8686
ArgsParseNode argsNode,
87-
String methodNameForBlock) {
88-
super(context, parent, environment, source, parserContext, currentNode);
87+
String methodNameForBlock,
88+
RubyDeferredWarnings rubyWarnings) {
89+
super(context, parent, environment, source, parserContext, currentNode, rubyWarnings);
8990
this.isBlock = isBlock;
9091
this.argsNode = argsNode;
9192
this.methodNameForBlock = methodNameForBlock;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
***** BEGIN LICENSE BLOCK *****
3+
* Version: EPL 2.0/GPL 2.0/LGPL 2.1
4+
*
5+
* The contents of this file are subject to the Eclipse Public
6+
* License Version 2.0 (the "License"); you may not use this file
7+
* except in compliance with the License. You may obtain a copy of
8+
* the License at http://www.eclipse.org/legal/epl-v20.html
9+
*
10+
* Software distributed under the License is distributed on an "AS
11+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
12+
* implied. See the License for the specific language governing
13+
* rights and limitations under the License.
14+
*
15+
* Copyright (C) 2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
16+
* Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
17+
* Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
18+
* Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
19+
*
20+
* Alternatively, the contents of this file may be used under the terms of
21+
* either of the GNU General Public License Version 2 or later (the "GPL"),
22+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23+
* in which case the provisions of the GPL or the LGPL are applicable instead
24+
* of those above. If you wish to allow use of your version of this file only
25+
* under the terms of either the GPL or the LGPL, and not to allow others to
26+
* use your version of this file under the terms of the EPL, indicate your
27+
* decision by deleting the provisions above and replace them with the notice
28+
* and other provisions required by the GPL or the LGPL. If you do not delete
29+
* the provisions above, a recipient may use your version of this file under
30+
* the terms of any one of the EPL, the GPL or the LGPL.
31+
***** END LICENSE BLOCK *****/
32+
package org.truffleruby.parser;
33+
34+
import java.util.ArrayList;
35+
import java.util.List;
36+
37+
import org.joni.WarnCallback;
38+
39+
public class RubyDeferredWarnings implements WarnCallback {
40+
41+
public List<WarningMessage> warnings = new ArrayList<>();
42+
43+
public enum Verbosity {
44+
VERBOSE, // -W2
45+
NON_VERBOSE // -W1
46+
}
47+
48+
public class WarningMessage {
49+
public final Verbosity verbosity;
50+
private final String fileName;
51+
private final Integer lineNumber;
52+
private final String message;
53+
54+
public WarningMessage(Verbosity verbosity, String fileName, Integer lineNumber, String message) {
55+
this.verbosity = verbosity;
56+
this.fileName = fileName;
57+
this.lineNumber = lineNumber;
58+
this.message = message;
59+
}
60+
61+
public String getWarningMessage() {
62+
StringBuilder buffer = new StringBuilder();
63+
if (fileName != null) {
64+
buffer.append(fileName);
65+
if (lineNumber != null) {
66+
buffer.append(':').append(lineNumber).append(": ");
67+
} else {
68+
buffer.append(' ');
69+
}
70+
}
71+
buffer.append("warning: ").append(message).append('\n');
72+
return buffer.toString();
73+
}
74+
75+
}
76+
77+
@Override
78+
public void warn(String message) {
79+
warn(null, message);
80+
}
81+
82+
/** Prints a warning, unless $VERBOSE is nil. */
83+
public void warn(String fileName, int lineNumber, String message) {
84+
warnings.add(new WarningMessage(Verbosity.NON_VERBOSE, fileName, lineNumber, message));
85+
}
86+
87+
/** Prints a warning, unless $VERBOSE is nil. */
88+
public void warn(String fileName, String message) {
89+
warnings.add(new WarningMessage(Verbosity.NON_VERBOSE, fileName, null, message));
90+
}
91+
92+
/** Prints a warning, only if $VERBOSE is true. */
93+
public void warning(String fileName, int lineNumber, String message) {
94+
warnings.add(
95+
new WarningMessage(
96+
Verbosity.VERBOSE,
97+
fileName,
98+
lineNumber,
99+
message));
100+
}
101+
102+
}

src/main/java/org/truffleruby/parser/RubyWarnings.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public void warn(String fileName, int lineNumber, String message) {
6969
return;
7070
}
7171

72-
StringBuilder buffer = new StringBuilder(100);
72+
StringBuilder buffer = new StringBuilder();
7373

7474
buffer.append(fileName).append(':').append(lineNumber).append(": ");
7575
buffer.append("warning: ").append(message).append('\n');
@@ -82,7 +82,7 @@ public void warn(String fileName, String message) {
8282
return;
8383
}
8484

85-
StringBuilder buffer = new StringBuilder(100);
85+
StringBuilder buffer = new StringBuilder();
8686

8787
if (fileName != null) {
8888
buffer.append(fileName).append(' ');
@@ -91,7 +91,7 @@ public void warn(String fileName, String message) {
9191
printWarning(buffer.toString());
9292
}
9393

94-
/** Prints a warning, only in verbose mode. */
94+
/** Prints a warning, only if $VERBOSE is true. */
9595
public void warning(String fileName, int lineNumber, String message) {
9696
if (!isVerbose()) {
9797
return;

0 commit comments

Comments
 (0)