I can see how it would be useful, but i do think it should be possible to disable and/or warn about <br><div class="gmail_quote"><div dir="ltr">On Thu, Mar 24, 2016 at 7:40 PM Jason Molenda <<a href="mailto:jmolenda@apple.com">jmolenda@apple.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The specific example Jim gave (./->) is a very common complaint of people coming from gdb.<br>
<br>
gdb's hand-rolled parser would realize that when you -> on an object, that doesn't make sense and silently correct it to . for you. In practice, when you're examining local variables, you often don't remember whether something is an object or a pointer to an object - especially when you are dereferencing down a few levels (e.g. "p myvar->subelem.valcontainer->value").<br>
<br>
Because lldb uses clang, we have to follow the rules of the language (for the most part) - this is likely the only way we could accomplish something similar in lldb.<br>
<br>
<br>
> On Mar 24, 2016, at 7:23 PM, Zachary Turner via lldb-commits <<a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a>> wrote:<br>
><br>
> This seems like an odd thing to do by default. Is there going to be a setting to turn this off? Seems to me like off should be default<br>
><br>
> An enumerated setting would be even nicer, where one option is "report" that just doesn't apply any FixIts, but prints a message saying "did you mean Foo->bar()?"<br>
> On Thu, Mar 24, 2016 at 7:02 PM Jim Ingham via lldb-commits <<a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a>> wrote:<br>
> Author: jingham<br>
> Date: Thu Mar 24 20:57:14 2016<br>
> New Revision: 264379<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=264379&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=264379&view=rev</a><br>
> Log:<br>
> Use Clang's FixItHints to correct expressions with "trivial" mistakes (e.g. "." for "->".)<br>
> This feature is controlled by an expression command option, a target property and the<br>
> SBExpressionOptions setting. FixIt's are only applied to UserExpressions, not UtilityFunctions,<br>
> those you have to get right when you make them.<br>
><br>
> This is just a first stage. At present the fixits are applied silently. The next step<br>
> is to tell the user about the applied fixit.<br>
><br>
> <rdar://problem/25351938><br>
><br>
> Added:<br>
> lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/<br>
> lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/Makefile<br>
> lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py<br>
> lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/main.cpp<br>
> lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h<br>
> Modified:<br>
> lldb/trunk/include/lldb/API/SBExpressionOptions.h<br>
> lldb/trunk/include/lldb/Expression/DiagnosticManager.h<br>
> lldb/trunk/include/lldb/Expression/ExpressionParser.h<br>
> lldb/trunk/include/lldb/Target/Target.h<br>
> lldb/trunk/lldb.xcodeproj/project.pbxproj<br>
> lldb/trunk/scripts/interface/SBExpressionOptions.i<br>
> lldb/trunk/source/API/SBExpressionOptions.cpp<br>
> lldb/trunk/source/Commands/CommandObjectExpression.cpp<br>
> lldb/trunk/source/Commands/CommandObjectExpression.h<br>
> lldb/trunk/source/Expression/DiagnosticManager.cpp<br>
> lldb/trunk/source/Expression/UserExpression.cpp<br>
> lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp<br>
> lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h<br>
> lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp<br>
> lldb/trunk/source/Target/Target.cpp<br>
><br>
> Modified: lldb/trunk/include/lldb/API/SBExpressionOptions.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBExpressionOptions.h?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBExpressionOptions.h?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/include/lldb/API/SBExpressionOptions.h (original)<br>
> +++ lldb/trunk/include/lldb/API/SBExpressionOptions.h Thu Mar 24 20:57:14 2016<br>
> @@ -110,6 +110,12 @@ public:<br>
><br>
> void<br>
> SetPrefix (const char *prefix);<br>
> +<br>
> + void<br>
> + SetAutoApplyFixIts(bool b = true);<br>
> +<br>
> + bool<br>
> + GetAutoApplyFixIts();<br>
><br>
> protected:<br>
><br>
><br>
> Modified: lldb/trunk/include/lldb/Expression/DiagnosticManager.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/DiagnosticManager.h?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/DiagnosticManager.h?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/include/lldb/Expression/DiagnosticManager.h (original)<br>
> +++ lldb/trunk/include/lldb/Expression/DiagnosticManager.h Thu Mar 24 20:57:14 2016<br>
> @@ -38,15 +38,82 @@ enum DiagnosticSeverity<br>
><br>
> const uint32_t LLDB_INVALID_COMPILER_ID = UINT32_MAX;<br>
><br>
> -struct Diagnostic<br>
> +class Diagnostic<br>
> {<br>
> - std::string message;<br>
> - uint32_t compiler_id; // Compiler-specific diagnostic ID<br>
> - DiagnosticSeverity severity;<br>
> - DiagnosticOrigin origin;<br>
> +friend class DiagnosticManager;<br>
> +<br>
> +public:<br>
> + DiagnosticOrigin getKind() const { return m_origin; }<br>
> +<br>
> + static bool classof(const Diagnostic *diag)<br>
> + {<br>
> + DiagnosticOrigin kind = diag->getKind();<br>
> + switch (kind)<br>
> + {<br>
> + case eDiagnosticOriginUnknown:<br>
> + case eDiagnosticOriginLLDB:<br>
> + case eDiagnosticOriginGo:<br>
> + case eDiagnosticOriginLLVM:<br>
> + return true;<br>
> + case eDiagnosticOriginClang:<br>
> + case eDiagnosticOriginSwift:<br>
> + return false;<br>
> + }<br>
> + }<br>
> +<br>
> + Diagnostic(const char *message, DiagnosticSeverity severity, DiagnosticOrigin origin, uint32_t compiler_id) :<br>
> + m_message(message),<br>
> + m_severity(severity),<br>
> + m_origin(origin),<br>
> + m_compiler_id(compiler_id)<br>
> + {<br>
> + }<br>
> +<br>
> + Diagnostic(const Diagnostic &rhs) :<br>
> + m_message(rhs.m_message),<br>
> + m_severity(rhs.m_severity),<br>
> + m_origin(rhs.m_origin),<br>
> + m_compiler_id(rhs.m_compiler_id)<br>
> + {<br>
> + }<br>
> +<br>
> + virtual ~Diagnostic() = default;<br>
> +<br>
> + virtual bool HasFixIts () const { return false; }<br>
> +<br>
> + DiagnosticSeverity<br>
> + GetSeverity() const<br>
> + {<br>
> + return m_severity;<br>
> + }<br>
> +<br>
> + uint32_t<br>
> + GetCompilerID() const<br>
> + {<br>
> + return m_compiler_id;<br>
> + }<br>
> +<br>
> + const char *<br>
> + GetMessage() const<br>
> + {<br>
> + return m_message.c_str();<br>
> + }<br>
> +<br>
> + void AppendMessage(const char *message, bool precede_with_newline = true)<br>
> + {<br>
> + if (precede_with_newline)<br>
> + m_message.push_back('\n');<br>
> + m_message.append(message);<br>
> + }<br>
> +<br>
> +protected:<br>
> + std::string m_message;<br>
> + DiagnosticSeverity m_severity;<br>
> + DiagnosticOrigin m_origin;<br>
> + uint32_t m_compiler_id; // Compiler-specific diagnostic ID<br>
> };<br>
><br>
> -typedef std::vector<Diagnostic> DiagnosticList;<br>
> +typedef std::vector<Diagnostic *> DiagnosticList;<br>
><br>
> class DiagnosticManager<br>
> {<br>
> @@ -55,19 +122,47 @@ public:<br>
> Clear()<br>
> {<br>
> m_diagnostics.clear();<br>
> + m_auto_apply_fixits = true;<br>
> + m_fixed_expression.clear();<br>
> }<br>
><br>
> + // The diagnostic manager holds a list of diagnostics, which are owned by the manager.<br>
> const DiagnosticList &<br>
> Diagnostics()<br>
> {<br>
> return m_diagnostics;<br>
> }<br>
> -<br>
> +<br>
> + ~DiagnosticManager()<br>
> + {<br>
> + for (Diagnostic *diag : m_diagnostics)<br>
> + {<br>
> + delete diag;<br>
> + }<br>
> + }<br>
> +<br>
> + bool<br>
> + HasFixIts()<br>
> + {<br>
> + for (Diagnostic *diag : m_diagnostics)<br>
> + {<br>
> + if (diag->HasFixIts())<br>
> + return true;<br>
> + }<br>
> + return false;<br>
> + }<br>
> +<br>
> void<br>
> AddDiagnostic(const char *message, DiagnosticSeverity severity, DiagnosticOrigin origin,<br>
> uint32_t compiler_id = LLDB_INVALID_COMPILER_ID)<br>
> {<br>
> - m_diagnostics.push_back({std::string(message), compiler_id, severity, origin});<br>
> + m_diagnostics.push_back(new Diagnostic(message, severity, origin, compiler_id));<br>
> + }<br>
> +<br>
> + void<br>
> + AddDiagnostic(Diagnostic *diagnostic)<br>
> + {<br>
> + m_diagnostics.push_back(diagnostic);<br>
> }<br>
><br>
> size_t<br>
> @@ -80,11 +175,10 @@ public:<br>
> {<br>
> if (m_diagnostics.size())<br>
> {<br>
> - m_diagnostics.back().message.push_back('\n');<br>
> - m_diagnostics.back().message.append(cstr);<br>
> + m_diagnostics.back()->AppendMessage(cstr);<br>
> }<br>
> }<br>
> -<br>
> +<br>
> // Returns a string containing errors in this format:<br>
> //<br>
> // "error: error text\n<br>
> @@ -95,9 +189,36 @@ public:<br>
><br>
> void<br>
> Dump(Log *log);<br>
> +<br>
> + const std::string &<br>
> + GetFixedExpression()<br>
> + {<br>
> + return m_fixed_expression;<br>
> + }<br>
> +<br>
> + // Moves fixed_expression to the internal storage.<br>
> + void<br>
> + SetFixedExpression(std::string fixed_expression)<br>
> + {<br>
> + m_fixed_expression = std::move(fixed_expression);<br>
> + fixed_expression.clear();<br>
> + }<br>
> +<br>
> + void<br>
> + SetAutoApplyFixIts(bool auto_apply)<br>
> + {<br>
> + m_auto_apply_fixits = auto_apply;<br>
> + }<br>
> +<br>
> + bool ShouldAutoApplyFixIts()<br>
> + {<br>
> + return m_auto_apply_fixits;<br>
> + }<br>
><br>
> -private:<br>
> +protected:<br>
> DiagnosticList m_diagnostics;<br>
> + std::string m_fixed_expression;<br>
> + bool m_auto_apply_fixits = true;<br>
> };<br>
> }<br>
><br>
><br>
> Modified: lldb/trunk/include/lldb/Expression/ExpressionParser.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ExpressionParser.h?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ExpressionParser.h?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/include/lldb/Expression/ExpressionParser.h (original)<br>
> +++ lldb/trunk/include/lldb/Expression/ExpressionParser.h Thu Mar 24 20:57:14 2016<br>
> @@ -58,7 +58,7 @@ public:<br>
> /// wrap the expression in anything at all.<br>
> ///<br>
> /// @param[in] diagnostic_manager<br>
> - /// The stream to print errors to.<br>
> + /// The diagnostic manager in which to store the errors and warnings.<br>
> ///<br>
> /// @return<br>
> /// The number of errors encountered during parsing. 0 means<br>
> @@ -66,6 +66,23 @@ public:<br>
> //------------------------------------------------------------------<br>
> virtual unsigned<br>
> Parse(DiagnosticManager &diagnostic_manager) = 0;<br>
> +<br>
> + //------------------------------------------------------------------<br>
> + /// Try to use the FixIts in the diagnostic_manager to rewrite the<br>
> + /// expression. If successful, the rewritten expression is stored<br>
> + /// in the diagnostic_manager, get it out with GetFixedExpression.<br>
> + ///<br>
> + /// @param[in] diagnostic_manager<br>
> + /// The diagnostic manager containing fixit's to apply.<br>
> + ///<br>
> + /// @return<br>
> + /// \b true if the rewrite was successful, \b false otherwise.<br>
> + //------------------------------------------------------------------<br>
> + virtual bool<br>
> + RewriteExpression(DiagnosticManager &diagnostic_manager)<br>
> + {<br>
> + return false;<br>
> + }<br>
><br>
> //------------------------------------------------------------------<br>
> /// Ready an already-parsed expression for execution, possibly<br>
><br>
> Modified: lldb/trunk/include/lldb/Target/Target.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/include/lldb/Target/Target.h (original)<br>
> +++ lldb/trunk/include/lldb/Target/Target.h Thu Mar 24 20:57:14 2016<br>
> @@ -149,6 +149,9 @@ public:<br>
> GetEnableAutoImportClangModules () const;<br>
><br>
> bool<br>
> + GetEnableAutoApplyFixIts () const;<br>
> +<br>
> + bool<br>
> GetEnableSyntheticValue () const;<br>
><br>
> uint32_t<br>
> @@ -271,6 +274,7 @@ public:<br>
> m_trap_exceptions (true),<br>
> m_generate_debug_info (false),<br>
> m_result_is_internal (false),<br>
> + m_auto_apply_fixits (true),<br>
> m_use_dynamic (lldb::eNoDynamicValues),<br>
> m_timeout_usec (default_timeout),<br>
> m_one_thread_timeout_usec (0),<br>
> @@ -541,6 +545,18 @@ public:<br>
> {<br>
> return m_result_is_internal;<br>
> }<br>
> +<br>
> + void<br>
> + SetAutoApplyFixIts(bool b)<br>
> + {<br>
> + m_auto_apply_fixits = b;<br>
> + }<br>
> +<br>
> + bool<br>
> + GetAutoApplyFixIts() const<br>
> + {<br>
> + return m_auto_apply_fixits;<br>
> + }<br>
><br>
> private:<br>
> ExecutionPolicy m_execution_policy;<br>
> @@ -558,6 +574,7 @@ private:<br>
> bool m_generate_debug_info;<br>
> bool m_ansi_color_errors;<br>
> bool m_result_is_internal;<br>
> + bool m_auto_apply_fixits;<br>
> lldb::DynamicValueType m_use_dynamic;<br>
> uint32_t m_timeout_usec;<br>
> uint32_t m_one_thread_timeout_usec;<br>
><br>
> Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)<br>
> +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Thu Mar 24 20:57:14 2016<br>
> @@ -2347,6 +2347,7 @@<br>
> 4C2479BE1BA39843009C9A7B /* ExpressionParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ExpressionParser.h; path = include/lldb/Expression/ExpressionParser.h; sourceTree = "<group>"; };<br>
> 4C29E77D1BA2403F00DFF855 /* ExpressionTypeSystemHelper.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ExpressionTypeSystemHelper.h; path = include/lldb/Expression/ExpressionTypeSystemHelper.h; sourceTree = "<group>"; };<br>
> 4C2FAE2E135E3A70001EDE44 /* SharedCluster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharedCluster.h; path = include/lldb/Utility/SharedCluster.h; sourceTree = "<group>"; };<br>
> + 4C3DA2301CA0BFB800CEB1D4 /* ClangDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangDiagnostic.h; path = ExpressionParser/Clang/ClangDiagnostic.h; sourceTree = "<group>"; };<br>
> 4C43DEF9110641F300E55CBF /* ThreadPlanShouldStopHere.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanShouldStopHere.h; path = include/lldb/Target/ThreadPlanShouldStopHere.h; sourceTree = "<group>"; };<br>
> 4C43DEFA110641F300E55CBF /* ThreadPlanShouldStopHere.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanShouldStopHere.cpp; path = source/Target/ThreadPlanShouldStopHere.cpp; sourceTree = "<group>"; };<br>
> 4C43DF8511069BFD00E55CBF /* ThreadPlanStepInRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepInRange.h; path = include/lldb/Target/ThreadPlanStepInRange.h; sourceTree = "<group>"; };<br>
> @@ -5288,6 +5289,7 @@<br>
> 4984BA0C1B97620B008658D4 /* Clang */ = {<br>
> isa = PBXGroup;<br>
> children = (<br>
> + 4C3DA2301CA0BFB800CEB1D4 /* ClangDiagnostic.h */,<br>
> 4C98D3E0118FB98F00E575D0 /* ClangFunctionCaller.h */,<br>
> 4C98D3DA118FB96F00E575D0 /* ClangFunctionCaller.cpp */,<br>
> 26BC7DC010F1B79500F91463 /* ClangExpressionHelper.h */,<br>
><br>
> Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/Makefile<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/Makefile?rev=264379&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/Makefile?rev=264379&view=auto</a><br>
> ==============================================================================<br>
> --- lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/Makefile (added)<br>
> +++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/Makefile Thu Mar 24 20:57:14 2016<br>
> @@ -0,0 +1,12 @@<br>
> +LEVEL = ../../make<br>
> +<br>
> +CXX_SOURCES := main.cpp<br>
> +<br>
> +# clang-3.5+ outputs FullDebugInfo by default for Darwin/FreeBSD<br>
> +# targets. Other targets do not, which causes this test to fail.<br>
> +# This flag enables FullDebugInfo for all targets.<br>
> +ifneq (,$(findstring clang,$(CC)))<br>
> + CFLAGS_EXTRAS += -fno-limit-debug-info<br>
> +endif<br>
> +<br>
> +include $(LEVEL)/Makefile.rules<br>
><br>
> Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py?rev=264379&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py?rev=264379&view=auto</a><br>
> ==============================================================================<br>
> --- lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py (added)<br>
> +++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py Thu Mar 24 20:57:14 2016<br>
> @@ -0,0 +1,77 @@<br>
> +"""<br>
> +Test calling an expression with errors that a FixIt can fix.<br>
> +"""<br>
> +<br>
> +from __future__ import print_function<br>
> +<br>
> +<br>
> +<br>
> +import lldb<br>
> +from lldbsuite.test.decorators import *<br>
> +from lldbsuite.test.lldbtest import *<br>
> +from lldbsuite.test import lldbutil<br>
> +<br>
> +class ExprCommandWithFixits(TestBase):<br>
> +<br>
> + mydir = TestBase.compute_mydir(__file__)<br>
> +<br>
> + def setUp(self):<br>
> + # Call super's setUp().<br>
> + TestBase.setUp(self)<br>
> +<br>
> + self.main_source = "main.cpp"<br>
> + self.main_source_spec = lldb.SBFileSpec (self.main_source)<br>
> +<br>
> + @skipUnlessDarwin<br>
> + def test(self):<br>
> + """Test calling a function that throws and ObjC exception."""<br>
> + self.build()<br>
> + self.try_expressions()<br>
> +<br>
> + def try_expressions(self):<br>
> + """Test calling expressions with errors that can be fixed by the FixIts."""<br>
> + exe_name = "a.out"<br>
> + exe = os.path.join(os.getcwd(), exe_name)<br>
> +<br>
> + target = self.dbg.CreateTarget(exe)<br>
> + self.assertTrue(target, VALID_TARGET)<br>
> +<br>
> + breakpoint = target.BreakpointCreateBySourceRegex('Stop here to evaluate expressions',self.main_source_spec)<br>
> + self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT)<br>
> +<br>
> + # Launch the process, and do not stop at the entry point.<br>
> + process = target.LaunchSimple (None, None, self.get_process_working_directory())<br>
> +<br>
> + self.assertTrue(process, PROCESS_IS_VALID)<br>
> +<br>
> + # Frame #0 should be at our breakpoint.<br>
> + threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint)<br>
> +<br>
> + self.assertTrue(len(threads) == 1)<br>
> + self.thread = threads[0]<br>
> +<br>
> + options = lldb.SBExpressionOptions()<br>
> + options.SetAutoApplyFixIts(True)<br>
> +<br>
> + frame = self.thread.GetFrameAtIndex(0)<br>
> +<br>
> + # Try with one error:<br>
> + value = frame.EvaluateExpression("my_pointer.first", options)<br>
> + self.assertTrue(value.IsValid())<br>
> + self.assertTrue(value.GetError().Success())<br>
> + self.assertTrue(value.GetValueAsUnsigned() == 10)<br>
> +<br>
> + # Try with two errors:<br>
> + two_error_expression = "my_pointer.second->a"<br>
> + value = frame.EvaluateExpression(two_error_expression, options)<br>
> + self.assertTrue(value.IsValid())<br>
> + self.assertTrue(value.GetError().Success())<br>
> + self.assertTrue(value.GetValueAsUnsigned() == 20)<br>
> +<br>
> + # Now turn off the fixits, and the expression should fail:<br>
> + options.SetAutoApplyFixIts(False)<br>
> + value = frame.EvaluateExpression("two_error_expression", options)<br>
> + self.assertTrue(value.IsValid())<br>
> + self.assertTrue(value.GetError().Fail())<br>
> +<br>
> +<br>
><br>
> Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/main.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/main.cpp?rev=264379&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/main.cpp?rev=264379&view=auto</a><br>
> ==============================================================================<br>
> --- lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/main.cpp (added)<br>
> +++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/fixits/main.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -0,0 +1,25 @@<br>
> +#include <stdio.h><br>
> +<br>
> +struct SubStruct<br>
> +{<br>
> + int a;<br>
> + int b;<br>
> +};<br>
> +<br>
> +struct MyStruct<br>
> +{<br>
> + int first;<br>
> + struct SubStruct second;<br>
> +};<br>
> +<br>
> +int<br>
> +main()<br>
> +{<br>
> + struct MyStruct my_struct = {10, {20, 30}};<br>
> + struct MyStruct *my_pointer = &my_struct;<br>
> + printf ("Stop here to evaluate expressions: %d %d %p\n", my_pointer->first, my_pointer->second.a, my_pointer);<br>
> + return 0;<br>
> +}<br>
> +<br>
> +<br>
> +<br>
><br>
> Modified: lldb/trunk/scripts/interface/SBExpressionOptions.i<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBExpressionOptions.i?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBExpressionOptions.i?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/scripts/interface/SBExpressionOptions.i (original)<br>
> +++ lldb/trunk/scripts/interface/SBExpressionOptions.i Thu Mar 24 20:57:14 2016<br>
> @@ -118,6 +118,15 @@ public:<br>
> %feature("docstring", "Sets the prefix to use for this expression. This prefix gets inserted after the 'target.expr-prefix' prefix contents, but before the wrapped expression function body.") SetPrefix;<br>
> void<br>
> SetPrefix (const char *prefix);<br>
> +<br>
> + %feature("docstring", "Sets whether to auto-apply FixIt hints to the expression being evaluated.") SetAutoApplyFixIts;<br>
> + void<br>
> + SetAutoApplyFixIts(bool b = true);<br>
> +<br>
> + %feature("docstring", "Gets whether to auto-apply FixIt hints to an expression.") GetAutoApplyFixIts;<br>
> + bool<br>
> + GetAutoApplyFixIts();<br>
> +<br>
><br>
> protected:<br>
><br>
><br>
> Modified: lldb/trunk/source/API/SBExpressionOptions.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBExpressionOptions.cpp?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBExpressionOptions.cpp?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/API/SBExpressionOptions.cpp (original)<br>
> +++ lldb/trunk/source/API/SBExpressionOptions.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -197,6 +197,18 @@ SBExpressionOptions::SetPrefix (const ch<br>
> return m_opaque_ap->SetPrefix(prefix);<br>
> }<br>
><br>
> +bool<br>
> +SBExpressionOptions::GetAutoApplyFixIts ()<br>
> +{<br>
> + return m_opaque_ap->GetAutoApplyFixIts ();<br>
> +}<br>
> +<br>
> +void<br>
> +SBExpressionOptions::SetAutoApplyFixIts (bool b)<br>
> +{<br>
> + return m_opaque_ap->SetAutoApplyFixIts (b);<br>
> +}<br>
> +<br>
> EvaluateExpressionOptions *<br>
> SBExpressionOptions::get() const<br>
> {<br>
><br>
> Modified: lldb/trunk/source/Commands/CommandObjectExpression.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectExpression.cpp?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectExpression.cpp?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Commands/CommandObjectExpression.cpp (original)<br>
> +++ lldb/trunk/source/Commands/CommandObjectExpression.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -61,6 +61,7 @@ CommandObjectExpression::CommandOptions:<br>
> { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},<br>
> { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug", 'g', OptionParser::eNoArgument , nullptr, nullptr, 0, eArgTypeNone, "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."},<br>
> { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specifies the Language to use when parsing the expression. If not set the target.language setting is used." },<br>
> + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "apply-fixits", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "If true, simple FixIt hints will be automatically applied to the expression." },<br>
> { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, nullptr, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."},<br>
> };<br>
><br>
> @@ -149,6 +150,17 @@ CommandObjectExpression::CommandOptions:<br>
> ignore_breakpoints = false;<br>
> break;<br>
><br>
> + case 'X':<br>
> + {<br>
> + bool success;<br>
> + bool tmp_value = Args::StringToBoolean(option_arg, true, &success);<br>
> + if (success)<br>
> + auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo;<br>
> + else<br>
> + error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);<br>
> + break;<br>
> + }<br>
> +<br>
> default:<br>
> error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);<br>
> break;<br>
> @@ -178,6 +190,7 @@ CommandObjectExpression::CommandOptions:<br>
> debug = false;<br>
> language = eLanguageTypeUnknown;<br>
> m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;<br>
> + auto_apply_fixits = eLazyBoolCalculate;<br>
> }<br>
><br>
> const OptionDefinition*<br>
> @@ -294,6 +307,14 @@ CommandObjectExpression::EvaluateExpress<br>
> options.SetTryAllThreads(m_command_options.try_all_threads);<br>
> options.SetDebug(m_command_options.debug);<br>
> options.SetLanguage(m_command_options.language);<br>
> +<br>
> + bool auto_apply_fixits;<br>
> + if (m_command_options.auto_apply_fixits == eLazyBoolCalculate)<br>
> + auto_apply_fixits = target->GetEnableAutoApplyFixIts();<br>
> + else<br>
> + auto_apply_fixits = m_command_options.auto_apply_fixits == eLazyBoolYes ? true : false;<br>
> +<br>
> + options.SetAutoApplyFixIts(auto_apply_fixits);<br>
><br>
> // If there is any chance we are going to stop and want to see<br>
> // what went wrong with our expression, we should generate debug info<br>
><br>
> Modified: lldb/trunk/source/Commands/CommandObjectExpression.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectExpression.h?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectExpression.h?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Commands/CommandObjectExpression.h (original)<br>
> +++ lldb/trunk/source/Commands/CommandObjectExpression.h Thu Mar 24 20:57:14 2016<br>
> @@ -14,13 +14,13 @@<br>
> // C++ Includes<br>
> // Other libraries and framework includes<br>
> // Project includes<br>
> +#include "lldb/lldb-private-enumerations.h"<br>
> #include "lldb/Core/IOHandler.h"<br>
> #include "lldb/Interpreter/CommandObject.h"<br>
> #include "lldb/Interpreter/OptionGroupBoolean.h"<br>
> #include "lldb/Interpreter/OptionGroupFormat.h"<br>
> #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"<br>
> #include "lldb/Target/ExecutionContext.h"<br>
> -<br>
> namespace lldb_private {<br>
><br>
> class CommandObjectExpression :<br>
> @@ -63,6 +63,7 @@ public:<br>
> bool try_all_threads;<br>
> lldb::LanguageType language;<br>
> LanguageRuntimeDescriptionDisplayVerbosity m_verbosity;<br>
> + LazyBool auto_apply_fixits;<br>
> };<br>
><br>
> CommandObjectExpression (CommandInterpreter &interpreter);<br>
><br>
> Modified: lldb/trunk/source/Expression/DiagnosticManager.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/DiagnosticManager.cpp?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/DiagnosticManager.cpp?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Expression/DiagnosticManager.cpp (original)<br>
> +++ lldb/trunk/source/Expression/DiagnosticManager.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -52,10 +52,10 @@ DiagnosticManager::GetString(char separa<br>
> {<br>
> std::string ret;<br>
><br>
> - for (const Diagnostic &diagnostic : Diagnostics())<br>
> + for (const Diagnostic *diagnostic : Diagnostics())<br>
> {<br>
> - ret.append(StringForSeverity(diagnostic.severity));<br>
> - ret.append(diagnostic.message);<br>
> + ret.append(StringForSeverity(diagnostic->GetSeverity()));<br>
> + ret.append(diagnostic->GetMessage());<br>
> ret.push_back(separator);<br>
> }<br>
><br>
><br>
> Modified: lldb/trunk/source/Expression/UserExpression.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/UserExpression.cpp?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/UserExpression.cpp?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Expression/UserExpression.cpp (original)<br>
> +++ lldb/trunk/source/Expression/UserExpression.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -253,6 +253,7 @@ UserExpression::Evaluate (ExecutionConte<br>
> }<br>
><br>
> DiagnosticManager diagnostic_manager;<br>
> + diagnostic_manager.SetAutoApplyFixIts(options.GetAutoApplyFixIts());<br>
><br>
> if (!user_expression_sp->Parse(diagnostic_manager, exe_ctx, execution_policy, keep_expression_in_memory,<br>
> generate_debug_info))<br>
><br>
> Added: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h?rev=264379&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h?rev=264379&view=auto</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h (added)<br>
> +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h Thu Mar 24 20:57:14 2016<br>
> @@ -0,0 +1,59 @@<br>
> +//===-- DiagnosticManager.h -------------------------------------*- C++ -*-===//<br>
> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===----------------------------------------------------------------------===//<br>
> +<br>
> +#ifndef lldb_ClangDiagnostic_h<br>
> +#define lldb_ClangDiagnostic_h<br>
> +<br>
> +#include <vector><br>
> +<br>
> +#include "clang/Basic/Diagnostic.h"<br>
> +<br>
> +#include "lldb/lldb-defines.h"<br>
> +#include "lldb/lldb-types.h"<br>
> +<br>
> +#include "lldb/Expression/DiagnosticManager.h"<br>
> +<br>
> +namespace lldb_private<br>
> +{<br>
> +<br>
> +typedef std::vector<clang::FixItHint> FixItList;<br>
> +<br>
> +class ClangDiagnostic : public Diagnostic<br>
> +{<br>
> +public:<br>
> + static inline bool classof(const ClangDiagnostic *) { return true; }<br>
> + static inline bool classof(const Diagnostic *diag) {<br>
> + return diag->getKind() == eDiagnosticOriginClang;<br>
> + }<br>
> +<br>
> + ClangDiagnostic(const char *message, DiagnosticSeverity severity, uint32_t compiler_id) :<br>
> + Diagnostic(message, severity, eDiagnosticOriginClang, compiler_id)<br>
> + {<br>
> + }<br>
> +<br>
> + virtual ~ClangDiagnostic() = default;<br>
> +<br>
> + bool HasFixIts () const override { return !m_fixit_vec.empty(); }<br>
> +<br>
> + void<br>
> + AddFixitHint (const clang::FixItHint &fixit)<br>
> + {<br>
> + m_fixit_vec.push_back(fixit);<br>
> + }<br>
> +<br>
> + const FixItList &<br>
> + FixIts() const<br>
> + {<br>
> + return m_fixit_vec;<br>
> + }<br>
> + FixItList m_fixit_vec;<br>
> +};<br>
> +<br>
> +} // namespace lldb_private<br>
> +#endif /* lldb_ClangDiagnostic_h */<br>
><br>
> Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (original)<br>
> +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -17,9 +17,12 @@<br>
> #include "clang/Basic/FileManager.h"<br>
> #include "clang/Basic/SourceLocation.h"<br>
> #include "clang/Basic/TargetInfo.h"<br>
> -#include "clang/Basic/Version.h"<br>
> +#include "clang/Basic/Version.h"<br>
> #include "clang/CodeGen/CodeGenAction.h"<br>
> #include "clang/CodeGen/ModuleBuilder.h"<br>
> +#include "clang/Edit/Commit.h"<br>
> +#include "clang/Edit/EditsReceiver.h"<br>
> +#include "clang/Edit/EditedSource.h"<br>
> #include "clang/Frontend/CompilerInstance.h"<br>
> #include "clang/Frontend/CompilerInvocation.h"<br>
> #include "clang/Frontend/FrontendActions.h"<br>
> @@ -30,6 +33,7 @@<br>
> #include "clang/Lex/Preprocessor.h"<br>
> #include "clang/Parse/ParseAST.h"<br>
> #include "clang/Rewrite/Frontend/FrontendActions.h"<br>
> +#include "clang/Rewrite/Core/Rewriter.h"<br>
> #include "clang/Sema/SemaConsumer.h"<br>
> #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"<br>
><br>
> @@ -54,6 +58,7 @@<br>
><br>
> // Project includes<br>
> #include "ClangExpressionParser.h"<br>
> +#include "ClangDiagnostic.h"<br>
><br>
> #include "ClangASTSource.h"<br>
> #include "ClangExpressionHelper.h"<br>
> @@ -175,24 +180,48 @@ public:<br>
> diag_str.push_back('\0');<br>
> const char *data = diag_str.data();<br>
><br>
> + DiagnosticSeverity severity;<br>
> + bool make_new_diagnostic = true;<br>
> +<br>
> switch (DiagLevel)<br>
> {<br>
> case DiagnosticsEngine::Level::Fatal:<br>
> case DiagnosticsEngine::Level::Error:<br>
> - m_manager->AddDiagnostic(data, eDiagnosticSeverityError, eDiagnosticOriginClang, Info.getID());<br>
> + severity = eDiagnosticSeverityError;<br>
> break;<br>
> case DiagnosticsEngine::Level::Warning:<br>
> - m_manager->AddDiagnostic(data, eDiagnosticSeverityWarning, eDiagnosticOriginClang, Info.getID());<br>
> + severity = eDiagnosticSeverityWarning;<br>
> break;<br>
> case DiagnosticsEngine::Level::Remark:<br>
> case DiagnosticsEngine::Level::Ignored:<br>
> - m_manager->AddDiagnostic(data, eDiagnosticSeverityRemark, eDiagnosticOriginClang, Info.getID());<br>
> + severity = eDiagnosticSeverityRemark;<br>
> break;<br>
> case DiagnosticsEngine::Level::Note:<br>
> m_manager->AppendMessageToDiagnostic(data);<br>
> + make_new_diagnostic = false;<br>
> + }<br>
> + if (make_new_diagnostic)<br>
> + {<br>
> + ClangDiagnostic *new_diagnostic = new ClangDiagnostic(data, severity, Info.getID());<br>
> + m_manager->AddDiagnostic(new_diagnostic);<br>
> +<br>
> + // Don't store away warning fixits, since the compiler doesn't have enough<br>
> + // context in an expression for the warning to be useful.<br>
> + // FIXME: Should we try to filter out FixIts that apply to our generated<br>
> + // code, and not the user's expression?<br>
> + if (severity == eDiagnosticSeverityError)<br>
> + {<br>
> + size_t num_fixit_hints = Info.getNumFixItHints();<br>
> + for (int i = 0; i < num_fixit_hints; i++)<br>
> + {<br>
> + const clang::FixItHint &fixit = Info.getFixItHint(i);<br>
> + if (!fixit.isNull())<br>
> + new_diagnostic->AddFixitHint(fixit);<br>
> + }<br>
> + }<br>
> }<br>
> }<br>
> -<br>
> +<br>
> m_passthrough->HandleDiagnostic(DiagLevel, Info);<br>
> }<br>
><br>
> @@ -666,6 +695,87 @@ ClangExpressionParser::Parse(DiagnosticM<br>
> return num_errors;<br>
> }<br>
><br>
> +bool<br>
> +ClangExpressionParser::RewriteExpression(DiagnosticManager &diagnostic_manager)<br>
> +{<br>
> + clang::SourceManager &source_manager = m_compiler->getSourceManager();<br>
> + clang::edit::EditedSource editor(source_manager, m_compiler->getLangOpts(), nullptr);<br>
> + clang::edit::Commit commit(editor);<br>
> + clang::Rewriter rewriter(source_manager, m_compiler->getLangOpts());<br>
> +<br>
> + class RewritesReceiver : public edit::EditsReceiver {<br>
> + Rewriter &rewrite;<br>
> +<br>
> + public:<br>
> + RewritesReceiver(Rewriter &in_rewrite) : rewrite(in_rewrite) { }<br>
> +<br>
> + void insert(SourceLocation loc, StringRef text) override {<br>
> + rewrite.InsertText(loc, text);<br>
> + }<br>
> + void replace(CharSourceRange range, StringRef text) override {<br>
> + rewrite.ReplaceText(range.getBegin(), rewrite.getRangeSize(range), text);<br>
> + }<br>
> + };<br>
> +<br>
> + RewritesReceiver rewrites_receiver(rewriter);<br>
> +<br>
> + const DiagnosticList &diagnostics = diagnostic_manager.Diagnostics();<br>
> + size_t num_diags = diagnostics.size();<br>
> + if (num_diags == 0)<br>
> + return false;<br>
> +<br>
> + for (const Diagnostic *diag : diagnostic_manager.Diagnostics())<br>
> + {<br>
> + const ClangDiagnostic *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag);<br>
> + if (diagnostic && diagnostic->HasFixIts())<br>
> + {<br>
> + for (const FixItHint &fixit : diagnostic->FixIts())<br>
> + {<br>
> + // This is cobbed from clang::Rewrite::FixItRewriter.<br>
> + if (fixit.CodeToInsert.empty())<br>
> + {<br>
> + if (fixit.InsertFromRange.isValid())<br>
> + {<br>
> + commit.insertFromRange(fixit.RemoveRange.getBegin(),<br>
> + fixit.InsertFromRange, /*afterToken=*/false,<br>
> + fixit.BeforePreviousInsertions);<br>
> + }<br>
> + else<br>
> + commit.remove(fixit.RemoveRange);<br>
> + }<br>
> + else<br>
> + {<br>
> + if (fixit.RemoveRange.isTokenRange() ||<br>
> + fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd())<br>
> + commit.replace(fixit.RemoveRange, fixit.CodeToInsert);<br>
> + else<br>
> + commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert,<br>
> + /*afterToken=*/false, fixit.BeforePreviousInsertions);<br>
> + }<br>
> + }<br>
> + }<br>
> + }<br>
> +<br>
> + // FIXME - do we want to try to propagate specific errors here?<br>
> + if (!commit.isCommitable())<br>
> + return false;<br>
> + else if (!editor.commit(commit))<br>
> + return false;<br>
> +<br>
> + // Now play all the edits, and stash the result in the diagnostic manager.<br>
> + editor.applyRewrites(rewrites_receiver);<br>
> + RewriteBuffer &main_file_buffer = rewriter.getEditBuffer(source_manager.getMainFileID());<br>
> +<br>
> + std::string fixed_expression;<br>
> + llvm::raw_string_ostream out_stream(fixed_expression);<br>
> +<br>
> + main_file_buffer.write(out_stream);<br>
> + out_stream.flush();<br>
> + diagnostic_manager.SetFixedExpression(fixed_expression);<br>
> +<br>
> + return true;<br>
> +}<br>
> +<br>
> static bool FindFunctionInModule (ConstString &mangled_name,<br>
> llvm::Module *module,<br>
> const char *orig_name)<br>
><br>
> Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h (original)<br>
> +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h Thu Mar 24 20:57:14 2016<br>
> @@ -73,6 +73,9 @@ public:<br>
> //------------------------------------------------------------------<br>
> unsigned<br>
> Parse(DiagnosticManager &diagnostic_manager) override;<br>
> +<br>
> + bool<br>
> + RewriteExpression(DiagnosticManager &diagnostic_manager) override;<br>
><br>
> //------------------------------------------------------------------<br>
> /// Ready an already-parsed expression for execution, possibly<br>
><br>
> Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp (original)<br>
> +++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -23,6 +23,7 @@<br>
> #include "ClangExpressionParser.h"<br>
> #include "ClangModulesDeclVendor.h"<br>
> #include "ClangPersistentVariables.h"<br>
> +#include "ClangDiagnostic.h"<br>
><br>
> #include "lldb/Core/ConstString.h"<br>
> #include "lldb/Core/Log.h"<br>
> @@ -358,8 +359,6 @@ ClangUserExpression::Parse(DiagnosticMan<br>
> diagnostic_manager.PutCString(eDiagnosticSeverityWarning, err.AsCString());<br>
> }<br>
><br>
> - StreamString m_transformed_stream;<br>
> -<br>
> ////////////////////////////////////<br>
> // Generate the expression<br>
> //<br>
> @@ -489,10 +488,38 @@ ClangUserExpression::Parse(DiagnosticMan<br>
> if (!exe_scope)<br>
> exe_scope = exe_ctx.GetTargetPtr();<br>
><br>
> - ClangExpressionParser parser(exe_scope, *this, generate_debug_info);<br>
> + // We use a shared pointer here so we can use the original parser - if it succeeds<br>
> + // or the rewrite parser we might make if it fails. But the parser_sp will never be empty.<br>
> +<br>
> + std::shared_ptr<ClangExpressionParser> parser_sp(new ClangExpressionParser(exe_scope, *this, generate_debug_info));<br>
><br>
> - unsigned num_errors = parser.Parse(diagnostic_manager);<br>
> + unsigned num_errors = parser_sp->Parse(diagnostic_manager);<br>
><br>
> + // Check here for FixItHints. If there are any try fixing the source and re-parsing...<br>
> + if (num_errors && diagnostic_manager.HasFixIts() && diagnostic_manager.ShouldAutoApplyFixIts())<br>
> + {<br>
> + if (parser_sp->RewriteExpression(diagnostic_manager))<br>
> + {<br>
> + std::string backup_source = std::move(m_transformed_text);<br>
> + m_transformed_text = diagnostic_manager.GetFixedExpression();<br>
> + // Make a new diagnostic manager and parser, and try again with the rewritten expression:<br>
> + // FIXME: It would be nice to reuse the parser we have but that doesn't seem to be possible.<br>
> + DiagnosticManager rewrite_manager;<br>
> + std::shared_ptr<ClangExpressionParser> rewrite_parser_sp(new ClangExpressionParser(exe_scope, *this, generate_debug_info));<br>
> + unsigned rewrite_errors = rewrite_parser_sp->Parse(rewrite_manager);<br>
> + if (rewrite_errors == 0)<br>
> + {<br>
> + diagnostic_manager.Clear();<br>
> + parser_sp = rewrite_parser_sp;<br>
> + num_errors = 0;<br>
> + }<br>
> + else<br>
> + {<br>
> + m_transformed_text = std::move(backup_source);<br>
> + }<br>
> + }<br>
> + }<br>
> +<br>
> if (num_errors)<br>
> {<br>
> diagnostic_manager.Printf(eDiagnosticSeverityError, "%u error%s parsing expression", num_errors,<br>
> @@ -508,8 +535,12 @@ ClangUserExpression::Parse(DiagnosticMan<br>
> //<br>
><br>
> {<br>
> - Error jit_error = parser.PrepareForExecution(m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,<br>
> - m_can_interpret, execution_policy);<br>
> + Error jit_error = parser_sp->PrepareForExecution(m_jit_start_addr,<br>
> + m_jit_end_addr,<br>
> + m_execution_unit_sp,<br>
> + exe_ctx,<br>
> + m_can_interpret,<br>
> + execution_policy);<br>
><br>
> if (!jit_error.Success())<br>
> {<br>
> @@ -524,7 +555,7 @@ ClangUserExpression::Parse(DiagnosticMan<br>
><br>
> if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel)<br>
> {<br>
> - Error static_init_error = parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx);<br>
> + Error static_init_error = parser_sp->RunStaticInitializers(m_execution_unit_sp, exe_ctx);<br>
><br>
> if (!static_init_error.Success())<br>
> {<br>
><br>
> Modified: lldb/trunk/source/Target/Target.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=264379&r1=264378&r2=264379&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=264379&r1=264378&r2=264379&view=diff</a><br>
> ==============================================================================<br>
> --- lldb/trunk/source/Target/Target.cpp (original)<br>
> +++ lldb/trunk/source/Target/Target.cpp Thu Mar 24 20:57:14 2016<br>
> @@ -3425,6 +3425,7 @@ g_properties[] =<br>
> { "debug-file-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , nullptr, nullptr, "List of directories to be searched when locating debug symbol files." },<br>
> { "clang-module-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , nullptr, nullptr, "List of directories to be searched when locating modules for Clang." },<br>
> { "auto-import-clang-modules" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Automatically load Clang modules referred to by the program." },<br>
> + { "auto-apply-fixits" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Automatically apply fixit hints to expressions." },<br>
> { "max-children-count" , OptionValue::eTypeSInt64 , false, 256 , nullptr, nullptr, "Maximum number of children to expand in any level of depth." },<br>
> { "max-string-summary-length" , OptionValue::eTypeSInt64 , false, 1024 , nullptr, nullptr, "Maximum number of characters to show when using %s in summary strings." },<br>
> { "max-memory-read-size" , OptionValue::eTypeSInt64 , false, 1024 , nullptr, nullptr, "Maximum number of bytes that 'memory read' will fetch before --force must be specified." },<br>
> @@ -3481,6 +3482,7 @@ enum<br>
> ePropertyDebugFileSearchPaths,<br>
> ePropertyClangModuleSearchPaths,<br>
> ePropertyAutoImportClangModules,<br>
> + ePropertyAutoApplyFixIts,<br>
> ePropertyMaxChildrenCount,<br>
> ePropertyMaxSummaryLength,<br>
> ePropertyMaxMemReadSize,<br>
> @@ -3853,6 +3855,13 @@ TargetProperties::GetEnableAutoImportCla<br>
> return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);<br>
> }<br>
><br>
> +bool<br>
> +TargetProperties::GetEnableAutoApplyFixIts() const<br>
> +{<br>
> + const uint32_t idx = ePropertyAutoApplyFixIts;<br>
> + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);<br>
> +}<br>
> +<br>
> bool<br>
> TargetProperties::GetEnableSyntheticValue () const<br>
> {<br>
><br>
><br>
> _______________________________________________<br>
> lldb-commits mailing list<br>
> <a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits</a><br>
> _______________________________________________<br>
> lldb-commits mailing list<br>
> <a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits</a><br>
<br>
</blockquote></div>